Unified · Split
| @@ -70,6 +70,7 @@ NATIVE_DEFINES_$(CONFIG_arm) += -DTCC_TARGET_ARM · 69 unmodified lines | ||
| 70 | 70 | NATIVE_DEFINES_$(CONFIG_arm_eabihf) += -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT |
| 71 | 71 | NATIVE_DEFINES_$(CONFIG_arm_eabi) += -DTCC_ARM_EABI |
| 72 | 72 | NATIVE_DEFINES_$(CONFIG_arm_vfp) += -DTCC_ARM_VFP |
| 73 | +NATIVE_DEFINES_$(CONFIG_arm64) += -DTCC_TARGET_ARM64 | |
| 73 | 74 | NATIVE_DEFINES += $(NATIVE_DEFINES_yes) |
| 74 | 75 | |
| 75 | 76 | ifeq ($(TOP),.) |
| @@ -86,6 +87,7 @@ ARM_VFP_CROSS = arm-linux-gnu-tcc$(EXESUF) · 10 unmodified lines | ||
| 86 | 87 | ARM_EABI_CROSS = arm-linux-gnueabi-tcc$(EXESUF) |
| 87 | 88 | ARM_EABIHF_CROSS = arm-linux-gnueabihf-tcc$(EXESUF) |
| 88 | 89 | ARM_CROSS = $(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS) |
| 90 | +ARM64_CROSS = arm64-tcc$(EXESUF) | |
| 89 | 91 | C67_CROSS = c67-tcc$(EXESUF) |
| 90 | 92 | |
| 91 | 93 | # 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 | ||
| 107 | 109 | WINCE_FILES = $(CORE_FILES) arm-gen.c tccpe.c |
| 108 | 110 | X86_64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h |
| 109 | 111 | ARM_FILES = $(CORE_FILES) arm-gen.c |
| 112 | +ARM64_FILES = $(CORE_FILES) arm64-gen.c | |
| 110 | 113 | C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c |
| 111 | 114 | |
| 112 | 115 | ifdef CONFIG_WIN64 |
| 113 | 116 | PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) |
| 114 | 117 | NATIVE_FILES=$(WIN64_FILES) |
| 115 | −PROGS_CROSS=$(WIN32_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS) | |
| 118 | +PROGS_CROSS=$(WIN32_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS) | |
| 116 | 119 | LIBTCC1_CROSS=lib/i386-win32/libtcc1.a |
| 117 | 120 | LIBTCC1=libtcc1.a |
| 118 | 121 | else ifdef CONFIG_WIN32 |
| 119 | 122 | PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) |
| 120 | 123 | NATIVE_FILES=$(WIN32_FILES) |
| 121 | −PROGS_CROSS=$(WIN64_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS) | |
| 124 | +PROGS_CROSS=$(WIN64_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS) | |
| 122 | 125 | LIBTCC1_CROSS=lib/x86_64-win32/libtcc1.a |
| 123 | 126 | LIBTCC1=libtcc1.a |
| 124 | 127 | else ifeq ($(ARCH),i386) |
| 125 | 128 | NATIVE_FILES=$(I386_FILES) |
| 126 | −PROGS_CROSS=$(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS) | |
| 129 | +PROGS_CROSS=$(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS) | |
| 127 | 130 | LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a |
| 128 | 131 | LIBTCC1=libtcc1.a |
| 129 | 132 | else ifeq ($(ARCH),x86-64) |
| 130 | 133 | NATIVE_FILES=$(X86_64_FILES) |
| 131 | −PROGS_CROSS=$(I386_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS) | |
| 134 | +PROGS_CROSS=$(I386_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS) | |
| 132 | 135 | LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a |
| 133 | 136 | LIBTCC1=libtcc1.a |
| 134 | 137 | else ifeq ($(ARCH),arm) |
| 135 | 138 | NATIVE_FILES=$(ARM_FILES) |
| 136 | −PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(C67_CROSS) $(WINCE_CROSS) | |
| 139 | +PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS) | |
| 140 | +LIBTCC1=libtcc1.a | |
| 141 | +LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a | |
| 142 | +else ifeq ($(ARCH),arm64) | |
| 143 | +NATIVE_FILES=$(ARM64_FILES) | |
| 144 | +PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS) | |
| 137 | 145 | LIBTCC1=libtcc1.a |
| 138 | 146 | LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a |
| 139 | 147 | endif |
| @@ -181,6 +189,7 @@ $(ARM_FPA_CROSS): DEFINES = -DTCC_TARGET_ARM · 41 unmodified lines | ||
| 181 | 189 | $(ARM_FPA_LD_CROSS)$(EXESUF): DEFINES = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12 |
| 182 | 190 | $(ARM_VFP_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_ARM_VFP -DCONFIG_MULTIARCHDIR="\"arm-linux-gnu\"" |
| 183 | 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 | 194 | $(I386_CROSS): $(I386_FILES) |
| 186 | 195 | $(X64_CROSS): $(X86_64_FILES) |
| @@ -189,6 +198,7 @@ $(WIN64_CROSS): $(WIN64_FILES) · 2 unmodified lines | ||
| 189 | 198 | $(WINCE_CROSS): $(WINCE_FILES) |
| 190 | 199 | $(C67_CROSS): $(C67_FILES) |
| 191 | 200 | $(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS): $(ARM_FILES) |
| 201 | +$(ARM64_CROSS): $(ARM64_FILES) | |
| 192 | 202 | |
| 193 | 203 | # libtcc generation and test |
| 194 | 204 | ifndef ONE_SOURCE |
| @@ -0,0 +1,1621 @@ | ||
| 1 | +/* | |
| 2 | + * A64 code generator for TCC | |
| 3 | + * | |
| 4 | + * Copyright (c) 2014-2015 Edmund Grimley Evans | |
| 5 | + * | |
| 6 | + * Copying and distribution of this file, with or without modification, | |
| 7 | + * are permitted in any medium without royalty provided the copyright | |
| 8 | + * notice and this notice are preserved. This file is offered as-is, | |
| 9 | + * without any warranty. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#ifdef TARGET_DEFS_ONLY | |
| 13 | + | |
| 14 | +// Number of registers available to allocator: | |
| 15 | +#define NB_REGS 28 // x0-x18, x30, v0-v7 | |
| 16 | + | |
| 17 | +#define TREG_R(x) (x) // x = 0..18 | |
| 18 | +#define TREG_R30 19 | |
| 19 | +#define TREG_F(x) (x + 20) // x = 0..7 | |
| 20 | + | |
| 21 | +// Register classes sorted from more general to more precise: | |
| 22 | +#define RC_INT (1 << 0) | |
| 23 | +#define RC_FLOAT (1 << 1) | |
| 24 | +#define RC_R(x) (1 << (2 + (x))) // x = 0..18 | |
| 25 | +#define RC_R30 (1 << 21) | |
| 26 | +#define RC_F(x) (1 << (22 + (x))) // x = 0..7 | |
| 27 | + | |
| 28 | +#define RC_IRET (RC_R(0)) // int return register class | |
| 29 | +#define RC_FRET (RC_F(0)) // float return register class | |
| 30 | + | |
| 31 | +#define REG_IRET (TREG_R(0)) // int return register number | |
| 32 | +#define REG_FRET (TREG_F(0)) // float return register number | |
| 33 | + | |
| 34 | +#define PTR_SIZE 8 | |
| 35 | + | |
| 36 | +#define LDOUBLE_SIZE 16 | |
| 37 | +#define LDOUBLE_ALIGN 16 | |
| 38 | + | |
| 39 | +#define MAX_ALIGN 16 | |
| 40 | + | |
| 41 | +#define CHAR_IS_UNSIGNED | |
| 42 | + | |
| 43 | +/******************************************************/ | |
| 44 | +/* ELF defines */ | |
| 45 | + | |
| 46 | +#define EM_TCC_TARGET EM_AARCH64 | |
| 47 | + | |
| 48 | +#define R_DATA_32 R_AARCH64_ABS32 | |
| 49 | +#define R_DATA_PTR R_AARCH64_ABS64 | |
| 50 | +#define R_JMP_SLOT R_AARCH64_JUMP_SLOT | |
| 51 | +#define R_COPY R_AARCH64_COPY | |
| 52 | + | |
| 53 | +#define ELF_START_ADDR 0x00400000 | |
| 54 | +#define ELF_PAGE_SIZE 0x1000 | |
| 55 | + | |
| 56 | +/******************************************************/ | |
| 57 | +#else /* ! TARGET_DEFS_ONLY */ | |
| 58 | +/******************************************************/ | |
| 59 | +#include "tcc.h" | |
| 60 | +#include <assert.h> | |
| 61 | + | |
| 62 | +ST_DATA const int reg_classes[NB_REGS] = { | |
| 63 | + RC_INT | RC_R(0), | |
| 64 | + RC_INT | RC_R(1), | |
| 65 | + RC_INT | RC_R(2), | |
| 66 | + RC_INT | RC_R(3), | |
| 67 | + RC_INT | RC_R(4), | |
| 68 | + RC_INT | RC_R(5), | |
| 69 | + RC_INT | RC_R(6), | |
| 70 | + RC_INT | RC_R(7), | |
| 71 | + RC_INT | RC_R(8), | |
| 72 | + RC_INT | RC_R(9), | |
| 73 | + RC_INT | RC_R(10), | |
| 74 | + RC_INT | RC_R(11), | |
| 75 | + RC_INT | RC_R(12), | |
| 76 | + RC_INT | RC_R(13), | |
| 77 | + RC_INT | RC_R(14), | |
| 78 | + RC_INT | RC_R(15), | |
| 79 | + RC_INT | RC_R(16), | |
| 80 | + RC_INT | RC_R(17), | |
| 81 | + RC_INT | RC_R(18), | |
| 82 | + RC_R30, // not in RC_INT as we make special use of x30 | |
| 83 | + RC_FLOAT | RC_F(0), | |
| 84 | + RC_FLOAT | RC_F(1), | |
| 85 | + RC_FLOAT | RC_F(2), | |
| 86 | + RC_FLOAT | RC_F(3), | |
| 87 | + RC_FLOAT | RC_F(4), | |
| 88 | + RC_FLOAT | RC_F(5), | |
| 89 | + RC_FLOAT | RC_F(6), | |
| 90 | + RC_FLOAT | RC_F(7) | |
| 91 | +}; | |
| 92 | + | |
| 93 | +#define IS_FREG(x) ((x) >= TREG_F(0)) | |
| 94 | + | |
| 95 | +static uint32_t intr(int r) | |
| 96 | +{ | |
| 97 | + assert(TREG_R(0) <= r && r <= TREG_R30); | |
| 98 | + return r < TREG_R30 ? r : 30; | |
| 99 | +} | |
| 100 | + | |
| 101 | +static uint32_t fltr(int r) | |
| 102 | +{ | |
| 103 | + assert(TREG_F(0) <= r && r <= TREG_F(7)); | |
| 104 | + return r - TREG_F(0); | |
| 105 | +} | |
| 106 | + | |
| 107 | +// Add an instruction to text section: | |
| 108 | +ST_FUNC void o(unsigned int c) | |
| 109 | +{ | |
| 110 | + int ind1 = ind + 4; | |
| 111 | + if (ind1 > cur_text_section->data_allocated) | |
| 112 | + section_realloc(cur_text_section, ind1); | |
| 113 | + *(uint32_t *)(cur_text_section->data + ind) = c; | |
| 114 | + ind = ind1; | |
| 115 | +} | |
| 116 | + | |
| 117 | +static int arm64_encode_bimm64(uint64_t x) | |
| 118 | +{ | |
| 119 | + int neg = x & 1; | |
| 120 | + int rep, pos, len; | |
| 121 | + | |
| 122 | + if (neg) | |
| 123 | + x = ~x; | |
| 124 | + if (!x) | |
| 125 | + return -1; | |
| 126 | + | |
| 127 | + if (x >> 2 == (x & (((uint64_t)1 << (64 - 2)) - 1))) | |
| 128 | + rep = 2, x &= ((uint64_t)1 << 2) - 1; | |
| 129 | + else if (x >> 4 == (x & (((uint64_t)1 << (64 - 4)) - 1))) | |
| 130 | + rep = 4, x &= ((uint64_t)1 << 4) - 1; | |
| 131 | + else if (x >> 8 == (x & (((uint64_t)1 << (64 - 8)) - 1))) | |
| 132 | + rep = 8, x &= ((uint64_t)1 << 8) - 1; | |
| 133 | + else if (x >> 16 == (x & (((uint64_t)1 << (64 - 16)) - 1))) | |
| 134 | + rep = 16, x &= ((uint64_t)1 << 16) - 1; | |
| 135 | + else if (x >> 32 == (x & (((uint64_t)1 << (64 - 32)) - 1))) | |
| 136 | + rep = 32, x &= ((uint64_t)1 << 32) - 1; | |
| 137 | + else | |
| 138 | + rep = 64; | |
| 139 | + | |
| 140 | + pos = 0; | |
| 141 | + if (!(x & (((uint64_t)1 << 32) - 1))) x >>= 32, pos += 32; | |
| 142 | + if (!(x & (((uint64_t)1 << 16) - 1))) x >>= 16, pos += 16; | |
| 143 | + if (!(x & (((uint64_t)1 << 8) - 1))) x >>= 8, pos += 8; | |
| 144 | + if (!(x & (((uint64_t)1 << 4) - 1))) x >>= 4, pos += 4; | |
| 145 | + if (!(x & (((uint64_t)1 << 2) - 1))) x >>= 2, pos += 2; | |
| 146 | + if (!(x & (((uint64_t)1 << 1) - 1))) x >>= 1, pos += 1; | |
| 147 | + | |
| 148 | + len = 0; | |
| 149 | + if (!(~x & (((uint64_t)1 << 32) - 1))) x >>= 32, len += 32; | |
| 150 | + if (!(~x & (((uint64_t)1 << 16) - 1))) x >>= 16, len += 16; | |
| 151 | + if (!(~x & (((uint64_t)1 << 8) - 1))) x >>= 8, len += 8; | |
| 152 | + if (!(~x & (((uint64_t)1 << 4) - 1))) x >>= 4, len += 4; | |
| 153 | + if (!(~x & (((uint64_t)1 << 2) - 1))) x >>= 2, len += 2; | |
| 154 | + if (!(~x & (((uint64_t)1 << 1) - 1))) x >>= 1, len += 1; | |
| 155 | + | |
| 156 | + if (x) | |
| 157 | + return -1; | |
| 158 | + if (neg) { | |
| 159 | + pos = (pos + len) & (rep - 1); | |
| 160 | + len = rep - len; | |
| 161 | + } | |
| 162 | + return ((0x1000 & rep << 6) | (((rep - 1) ^ 31) << 1 & 63) | | |
| 163 | + ((rep - pos) & (rep - 1)) << 6 | (len - 1)); | |
| 164 | +} | |
| 165 | + | |
| 166 | +static uint32_t arm64_movi(int r, uint64_t x) | |
| 167 | +{ | |
| 168 | + uint64_t m = 0xffff; | |
| 169 | + int e; | |
| 170 | + if (!(x & ~m)) | |
| 171 | + return 0x52800000 | r | x << 5; // movz w(r),#(x) | |
| 172 | + if (!(x & ~(m << 16))) | |
| 173 | + return 0x52a00000 | r | x >> 11; // movz w(r),#(x >> 16),lsl #16 | |
| 174 | + if (!(x & ~(m << 32))) | |
| 175 | + return 0xd2c00000 | r | x >> 27; // movz x(r),#(x >> 32),lsl #32 | |
| 176 | + if (!(x & ~(m << 48))) | |
| 177 | + return 0xd2e00000 | r | x >> 43; // movz x(r),#(x >> 48),lsl #48 | |
| 178 | + if ((x & ~m) == m << 16) | |
| 179 | + return (0x12800000 | r | | |
| 180 | + (~x << 5 & 0x1fffe0)); // movn w(r),#(~x) | |
| 181 | + if ((x & ~(m << 16)) == m) | |
| 182 | + return (0x12a00000 | r | | |
| 183 | + (~x >> 11 & 0x1fffe0)); // movn w(r),#(~x >> 16),lsl #16 | |
| 184 | + if (!~(x | m)) | |
| 185 | + return (0x92800000 | r | | |
| 186 | + (~x << 5 & 0x1fffe0)); // movn x(r),#(~x) | |
| 187 | + if (!~(x | m << 16)) | |
| 188 | + return (0x92a00000 | r | | |
| 189 | + (~x >> 11 & 0x1fffe0)); // movn x(r),#(~x >> 16),lsl #16 | |
| 190 | + if (!~(x | m << 32)) | |
| 191 | + return (0x92c00000 | r | | |
| 192 | + (~x >> 27 & 0x1fffe0)); // movn x(r),#(~x >> 32),lsl #32 | |
| 193 | + if (!~(x | m << 48)) | |
| 194 | + return (0x92e00000 | r | | |
| 195 | + (~x >> 43 & 0x1fffe0)); // movn x(r),#(~x >> 32),lsl #32 | |
| 196 | + if (!(x >> 32) && (e = arm64_encode_bimm64(x | x << 32)) >= 0) | |
| 197 | + return 0x320003e0 | r | (uint32_t)e << 10; // movi w(r),#(x) | |
| 198 | + if ((e = arm64_encode_bimm64(x)) >= 0) | |
| 199 | + return 0xb20003e0 | r | (uint32_t)e << 10; // movi x(r),#(x) | |
| 200 | + return 0; | |
| 201 | +} | |
| 202 | + | |
| 203 | +static void arm64_movimm(int r, uint64_t x) | |
| 204 | +{ | |
| 205 | + uint32_t i; | |
| 206 | + if ((i = arm64_movi(r, x))) | |
| 207 | + o(i); | |
| 208 | + else { | |
| 209 | + // This could be improved: | |
| 210 | + o(0x52800000 | r | (x & 0xffff) << 5); // movz w(r),#(x & 0xffff) | |
| 211 | + for (i = 1; i < 4; i++) | |
| 212 | + if (x >> 16 * i & 0xffff) { | |
| 213 | + o(0xf2800000 | r | (x >> 16 * i & 0xffff) << 5 | i << 21); | |
| 214 | + // movk w(r),#(*),lsl #(*) | |
| 215 | + } | |
| 216 | + | |
| 217 | + } | |
| 218 | +} | |
| 219 | + | |
| 220 | +// Patch all branches in list pointed to by t to branch to a: | |
| 221 | +ST_FUNC void gsym_addr(int t_, int a_) | |
| 222 | +{ | |
| 223 | + uint32_t t = t_; | |
| 224 | + uint32_t a = a_; | |
| 225 | + while (t) { | |
| 226 | + uint32_t *ptr = (uint32_t *)(cur_text_section->data + t); | |
| 227 | + uint32_t next = *ptr; | |
| 228 | + if (a - t + 0x8000000 >= 0x10000000) | |
| 229 | + tcc_error("branch out of range"); | |
| 230 | + *ptr = (a - t == 4 ? 0xd503201f : // nop | |
| 231 | + 0x14000000 | ((a - t) >> 2 & 0x3ffffff)); // b | |
| 232 | + t = next; | |
| 233 | + } | |
| 234 | +} | |
| 235 | + | |
| 236 | +// Patch all branches in list pointed to by t to branch to current location: | |
| 237 | +ST_FUNC void gsym(int t) | |
| 238 | +{ | |
| 239 | + gsym_addr(t, ind); | |
| 240 | +} | |
| 241 | + | |
| 242 | +static int arm64_type_size(int t) | |
| 243 | +{ | |
| 244 | + switch (t & VT_BTYPE) { | |
| 245 | + case VT_INT: return 2; | |
| 246 | + case VT_BYTE: return 0; | |
| 247 | + case VT_SHORT: return 1; | |
| 248 | + case VT_PTR: return 3; | |
| 249 | + case VT_ENUM: return 2; | |
| 250 | + case VT_FUNC: return 3; | |
| 251 | + case VT_FLOAT: return 2; | |
| 252 | + case VT_DOUBLE: return 3; | |
| 253 | + case VT_LDOUBLE: return 4; | |
| 254 | + case VT_BOOL: return 0; | |
| 255 | + case VT_LLONG: return 3; | |
| 256 | + } | |
| 257 | + assert(0); | |
| 258 | + return 0; | |
| 259 | +} | |
| 260 | + | |
| 261 | +static void gen_stack_addr(int reg, uint64_t off) | |
| 262 | +{ | |
| 263 | + arm64_movimm(30, off); // use x30 for offset | |
| 264 | + o(0x8b3e63e0 | reg); | |
| 265 | +} | |
| 266 | + | |
| 267 | +static void gen_load(int sg, int sz, int dst, int bas, uint64_t off) | |
| 268 | +{ | |
| 269 | + if (sz >= 2) | |
| 270 | + sg = 0; | |
| 271 | + if (!(off & ~(0xfff << sz))) | |
| 272 | + o(0x39400000 | dst | bas << 5 | off << (10 - sz) | | |
| 273 | + !!sg << 23 | sz << 30); | |
| 274 | + else if (off < 256 || -off <= 256) | |
| 275 | + o(0x38400000 | dst | bas << 5 | (off & 511) << 12 | | |
| 276 | + !!sg << 23 | sz << 30); | |
| 277 | + else { | |
| 278 | + arm64_movimm(30, off); // use x30 for offset | |
| 279 | + o(0x38206800 | dst | bas << 5 | 30 << 16 | | |
| 280 | + (!!sg + 1) << 22 | sz << 30); | |
| 281 | + } | |
| 282 | +} | |
| 283 | + | |
| 284 | +static void gen_fload(int sz, int dst, int bas, uint64_t off) | |
| 285 | +{ | |
| 286 | + if (!(off & ~(0xfff << sz))) | |
| 287 | + o(0x3d400000 | dst | bas << 5 | off << (10 - sz) | | |
| 288 | + (sz & 4) << 21 | (sz & 3) << 30); | |
| 289 | + else if (off < 256 || -off <= 256) | |
| 290 | + o(0x3c400000 | dst | bas << 5 | (off & 511) << 12 | | |
| 291 | + (sz & 4) << 21 | (sz & 3) << 30); | |
| 292 | + else { | |
| 293 | + arm64_movimm(30, off); // use x30 for offset | |
| 294 | + o(0x3c606800 | dst | bas << 5 | 30 << 16 | sz << 30 | (sz & 4) << 21); | |
| 295 | + } | |
| 296 | +} | |
| 297 | + | |
| 298 | +static void gen_sload(int reg, int size) | |
| 299 | +{ | |
| 300 | + // Use x30 for intermediate value in some cases. | |
| 301 | + switch (size) { | |
| 302 | + default: assert(0); break; | |
| 303 | + case 1: | |
| 304 | + gen_load(0, 0, reg, reg, 0); | |
| 305 | + break; | |
| 306 | + case 2: | |
| 307 | + gen_load(0, 1, reg, reg, 0); | |
| 308 | + break; | |
| 309 | + case 3: | |
| 310 | + gen_load(0, 1, 30, reg, 0); | |
| 311 | + gen_load(0, 0, reg, reg, 2); | |
| 312 | + o(0x2a0043c0 | reg | reg << 16); // orr x(reg),x30,x(reg),lsl #16 | |
| 313 | + break; | |
| 314 | + case 4: | |
| 315 | + gen_load(0, 2, reg, reg, 0); | |
| 316 | + break; | |
| 317 | + case 5: | |
| 318 | + gen_load(0, 2, 30, reg, 0); | |
| 319 | + gen_load(0, 0, reg, reg, 4); | |
| 320 | + o(0xaa0083c0 | reg | reg << 16); // orr x(reg),x30,x(reg),lsl #32 | |
| 321 | + break; | |
| 322 | + case 6: | |
| 323 | + gen_load(0, 2, 30, reg, 0); | |
| 324 | + gen_load(0, 1, reg, reg, 4); | |
| 325 | + o(0xaa0083c0 | reg | reg << 16); // orr x(reg),x30,x(reg),lsl #32 | |
| 326 | + break; | |
| 327 | + case 7: | |
| 328 | + gen_load(0, 2, 30, reg, 0); | |
| 329 | + gen_load(0, 2, reg, reg, 3); | |
| 330 | + o(0x53087c00 | reg | reg << 5); // lsr w(reg), w(reg), #8 | |
| 331 | + o(0xaa0083c0 | reg | reg << 16); // orr x(reg),x30,x(reg),lsl #32 | |
| 332 | + break; | |
| 333 | + case 8: | |
| 334 | + gen_load(0, 3, reg, reg, 0); | |
| 335 | + break; | |
| 336 | + case 9: | |
| 337 | + gen_load(0, 0, reg + 1, reg, 8); | |
| 338 | + gen_load(0, 3, reg, reg, 0); | |
| 339 | + break; | |
| 340 | + case 10: | |
| 341 | + gen_load(0, 1, reg + 1, reg, 8); | |
| 342 | + gen_load(0, 3, reg, reg, 0); | |
| 343 | + break; | |
| 344 | + case 11: | |
| 345 | + gen_load(0, 2, reg + 1, reg, 7); | |
| 346 | + o(0x53087c00 | (reg+1) | (reg+1) << 5); // lsr w(reg+1), w(reg+1), #8 | |
| 347 | + gen_load(0, 3, reg, reg, 0); | |
| 348 | + break; | |
| 349 | + case 12: | |
| 350 | + gen_load(0, 2, reg + 1, reg, 8); | |
| 351 | + gen_load(0, 3, reg, reg, 0); | |
| 352 | + break; | |
| 353 | + case 13: | |
| 354 | + gen_load(0, 3, reg + 1, reg, 5); | |
| 355 | + o(0xd358fc00 | (reg+1) | (reg+1) << 5); // lsr x(reg+1), x(reg+1), #24 | |
| 356 | + gen_load(0, 3, reg, reg, 0); | |
| 357 | + break; | |
| 358 | + case 14: | |
| 359 | + gen_load(0, 3, reg + 1, reg, 6); | |
| 360 | + o(0xd350fc00 | (reg+1) | (reg+1) << 5); // lsr x(reg+1), x(reg+1), #16 | |
| 361 | + gen_load(0, 3, reg, reg, 0); | |
| 362 | + break; | |
| 363 | + case 15: | |
| 364 | + gen_load(0, 3, reg + 1, reg, 7); | |
| 365 | + o(0xd348fc00 | (reg+1) | (reg+1) << 5); // lsr x(reg+1), x(reg+1), #8 | |
| 366 | + gen_load(0, 3, reg, reg, 0); | |
| 367 | + break; | |
| 368 | + case 16: | |
| 369 | + o(0xa9400000 | reg | (reg+1) << 10 | reg << 5); | |
| 370 | + // ldp x(reg),x(reg+1),[x(reg)] | |
| 371 | + break; | |
| 372 | + } | |
| 373 | +} | |
| 374 | + | |
| 375 | +static void gen_store(int sz, int dst, int bas, uint64_t off) | |
| 376 | +{ | |
| 377 | + if (!(off & ~(0xfff << sz))) | |
| 378 | + o(0x39000000 | dst | bas << 5 | off << (10 - sz) | sz << 30); | |
| 379 | + else if (off < 256 || -off <= 256) | |
| 380 | + o(0x38000000 | dst | bas << 5 | (off & 511) << 12 | sz << 30); | |
| 381 | + else { | |
| 382 | + arm64_movimm(30, off); // use x30 for offset | |
| 383 | + o(0x38206800 | dst | bas << 5 | 30 << 16 | sz << 30); | |
| 384 | + } | |
| 385 | +} | |
| 386 | + | |
| 387 | +static void gen_fstore(int sz, int dst, int bas, uint64_t off) | |
| 388 | +{ | |
| 389 | + if (!(off & ~(0xfff << sz))) | |
| 390 | + o(0x3d000000 | dst | bas << 5 | off << (10 - sz) | | |
| 391 | + (sz & 4) << 21 | (sz & 3) << 30); | |
| 392 | + else if (off < 256 || -off <= 256) | |
| 393 | + o(0x3c000000 | dst | bas << 5 | (off & 511) << 12 | | |
| 394 | + (sz & 4) << 21 | (sz & 3) << 30); | |
| 395 | + else { | |
| 396 | + arm64_movimm(30, off); // use x30 for offset | |
| 397 | + o(0x3c206800 | dst | bas << 5 | 30 << 16 | sz << 30 | (sz & 4) << 21); | |
| 398 | + } | |
| 399 | +} | |
| 400 | + | |
| 401 | +static void gen_addr(int r, Sym *sym, unsigned long addend) | |
| 402 | +{ | |
| 403 | +#if 0 | |
| 404 | + // This is normally the right way to do it, I think, | |
| 405 | + // but it does not work with "-run" when stdin or stderr is | |
| 406 | + // used by the program: "R_AARCH64_ADR_PREL_PG_HI21 relocation failed". | |
| 407 | + greloca(cur_text_section, sym, ind, R_AARCH64_ADR_PREL_PG_HI21, addend); | |
| 408 | + o(0x90000000 | r); | |
| 409 | + greloca(cur_text_section, sym, ind, R_AARCH64_ADD_ABS_LO12_NC, addend); | |
| 410 | + o(0x91000000 | r | r << 5); | |
| 411 | +#else | |
| 412 | + // This seems to work in all cases, unless you try to use an old buggy | |
| 413 | + // GCC for linking, which says: "unresolvable R_AARCH64_MOVW_UABS_G0_NC | |
| 414 | + // relocation against symbol `stderr@@GLIBC_2.17'". | |
| 415 | + greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G0_NC, addend); | |
| 416 | + o(0xf2800000 | r); // movk x(rt),#...,lsl #0 | |
| 417 | + greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G1_NC, addend); | |
| 418 | + o(0xf2a00000 | r); // movk x(rt),#...,lsl #16 | |
| 419 | + greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G2_NC, addend); | |
| 420 | + o(0xf2c00000 | r); // movk x(rt),#...,lsl #32 | |
| 421 | + greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G3, addend); | |
| 422 | + o(0xf2e00000 | r); // movk x(rt),#...,lsl #48 | |
| 423 | +#endif | |
| 424 | +} | |
| 425 | + | |
| 426 | +ST_FUNC void load(int r, SValue *sv) | |
| 427 | +{ | |
| 428 | + int svtt = sv->type.t; | |
| 429 | + int svr = sv->r & ~VT_LVAL_TYPE; | |
| 430 | + int svrv = svr & VT_VALMASK; | |
| 431 | + uint64_t svcul = (int32_t)sv->c.ul; | |
| 432 | + | |
| 433 | + if (svr == (VT_LOCAL | VT_LVAL)) { | |
| 434 | + if (IS_FREG(r)) | |
| 435 | + gen_fload(arm64_type_size(svtt), fltr(r), 29, svcul); | |
| 436 | + else | |
| 437 | + gen_load(!(svtt & VT_UNSIGNED), arm64_type_size(svtt), | |
| 438 | + intr(r), 29, svcul); | |
| 439 | + return; | |
| 440 | + } | |
| 441 | + | |
| 442 | + if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) { | |
| 443 | + if (IS_FREG(r)) | |
| 444 | + gen_fload(arm64_type_size(svtt), | |
| 445 | + fltr(r), intr(svrv), 0); | |
| 446 | + else | |
| 447 | + gen_load(!(svtt & VT_UNSIGNED), arm64_type_size(svtt), | |
| 448 | + intr(r), intr(svrv), 0); | |
| 449 | + return; | |
| 450 | + } | |
| 451 | + | |
| 452 | + if (svr == (VT_CONST | VT_LVAL | VT_SYM)) { | |
| 453 | + gen_addr(30, sv->sym, svcul); // use x30 for address | |
| 454 | + if (IS_FREG(r)) | |
| 455 | + gen_fload(arm64_type_size(svtt), fltr(r), 30, 0); | |
| 456 | + else | |
| 457 | + gen_load(!(svtt & VT_UNSIGNED), arm64_type_size(svtt), | |
| 458 | + intr(r), 30, 0); | |
| 459 | + return; | |
| 460 | + } | |
| 461 | + | |
| 462 | + if (svr == (VT_CONST | VT_SYM)) { | |
| 463 | + gen_addr(intr(r), sv->sym, svcul); | |
| 464 | + return; | |
| 465 | + } | |
| 466 | + | |
| 467 | + if (svr == VT_CONST) { | |
| 468 | + if ((svtt & VT_BTYPE) != VT_VOID) | |
| 469 | + arm64_movimm(intr(r), | |
| 470 | + arm64_type_size(svtt) == 3 ? sv->c.ull : svcul); | |
| 471 | + return; | |
| 472 | + } | |
| 473 | + | |
| 474 | + if (svr < VT_CONST) { | |
| 475 | + if (IS_FREG(r) && IS_FREG(svr)) | |
| 476 | + if (svtt == VT_LDOUBLE) | |
| 477 | + o(0x4ea01c00 | fltr(r) | fltr(svr) << 5); | |
| 478 | + // mov v(r).16b,v(svr).16b | |
| 479 | + else | |
| 480 | + o(0x1e604000 | fltr(r) | fltr(svr) << 5); // fmov d(r),d(svr) | |
| 481 | + else if (!IS_FREG(r) && !IS_FREG(svr)) | |
| 482 | + o(0xaa0003e0 | intr(r) | intr(svr) << 16); // mov x(r),x(svr) | |
| 483 | + else | |
| 484 | + assert(0); | |
| 485 | + return; | |
| 486 | + } | |
| 487 | + | |
| 488 | + if (svr == VT_LOCAL) { | |
| 489 | + if (-svcul < 0x1000) | |
| 490 | + o(0xd10003a0 | intr(r) | -svcul << 10); // sub x(r),x29,#... | |
| 491 | + else { | |
| 492 | + arm64_movimm(30, -svcul); // use x30 for offset | |
| 493 | + o(0xcb0003a0 | intr(r) | 30 << 16); // sub x(r),x29,x30 | |
| 494 | + } | |
| 495 | + return; | |
| 496 | + } | |
| 497 | + | |
| 498 | + if (svr == VT_JMP || svr == VT_JMPI) { | |
| 499 | + int t = (svr == VT_JMPI); | |
| 500 | + arm64_movimm(intr(r), t); | |
| 501 | + o(0x14000002); // b .+8 | |
| 502 | + gsym(svcul); | |
| 503 | + arm64_movimm(intr(r), t ^ 1); | |
| 504 | + return; | |
| 505 | + } | |
| 506 | + | |
| 507 | + if (svr == (VT_LLOCAL | VT_LVAL)) { | |
| 508 | + gen_load(0, 3, 30, 29, svcul); // use x30 for offset | |
| 509 | + if (IS_FREG(r)) | |
| 510 | + gen_fload(arm64_type_size(svtt), fltr(r), 30, 0); | |
| 511 | + else | |
| 512 | + gen_load(!(svtt & VT_UNSIGNED), arm64_type_size(svtt), | |
| 513 | + intr(r), 30, 0); | |
| 514 | + return; | |
| 515 | + } | |
| 516 | + | |
| 517 | + printf("load(%x, (%x, %x, %llx))\n", r, svtt, sv->r, (long long)svcul); | |
| 518 | + assert(0); | |
| 519 | +} | |
| 520 | + | |
| 521 | +ST_FUNC void store(int r, SValue *sv) | |
| 522 | +{ | |
| 523 | + int svtt = sv->type.t; | |
| 524 | + int svr = sv->r & ~VT_LVAL_TYPE; | |
| 525 | + int svrv = svr & VT_VALMASK; | |
| 526 | + uint64_t svcul = (int32_t)sv->c.ul; | |
| 527 | + | |
| 528 | + if (svr == (VT_LOCAL | VT_LVAL)) { | |
| 529 | + if (IS_FREG(r)) | |
| 530 | + gen_fstore(arm64_type_size(svtt), fltr(r), 29, svcul); | |
| 531 | + else | |
| 532 | + gen_store(arm64_type_size(svtt), intr(r), 29, svcul); | |
| 533 | + return; | |
| 534 | + } | |
| 535 | + | |
| 536 | + if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) { | |
| 537 | + if (IS_FREG(r)) | |
| 538 | + gen_fstore(arm64_type_size(svtt), fltr(r), intr(svrv), 0); | |
| 539 | + else | |
| 540 | + gen_store(arm64_type_size(svtt), intr(r), intr(svrv), 0); | |
| 541 | + return; | |
| 542 | + } | |
| 543 | + | |
| 544 | + if (svr == (VT_CONST | VT_LVAL | VT_SYM)) { | |
| 545 | + gen_addr(30, sv->sym, svcul); // use x30 for address | |
| 546 | + if (IS_FREG(r)) | |
| 547 | + gen_fstore(arm64_type_size(svtt), fltr(r), 30, 0); | |
| 548 | + else | |
| 549 | + gen_store(arm64_type_size(svtt), intr(r), 30, 0); | |
| 550 | + return; | |
| 551 | + } | |
| 552 | + | |
| 553 | + printf("store(%x, (%x, %x, %llx))\n", r, svtt, sv->r, (long long)svcul); | |
| 554 | + assert(0); | |
| 555 | +} | |
| 556 | + | |
| 557 | +static void arm64_gen_bl_or_b(int b) | |
| 558 | +{ | |
| 559 | + if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { | |
| 560 | + assert(!b); | |
| 561 | + if (vtop->r & VT_SYM) | |
| 562 | + greloc(cur_text_section, vtop->sym, ind, R_AARCH64_CALL26); | |
| 563 | + else | |
| 564 | + assert(0); | |
| 565 | + o(0x94000000); // bl . | |
| 566 | + } | |
| 567 | + else | |
| 568 | + o(0xd61f0000 | !b << 21 | intr(gv(RC_R30)) << 5); // br/blr | |
| 569 | +} | |
| 570 | + | |
| 571 | +static int arm64_hfa_aux(CType *type, int *fsize, int num) | |
| 572 | +{ | |
| 573 | + if (is_float(type->t)) { | |
| 574 | + int a, n = type_size(type, &a); | |
| 575 | + if (num >= 4 || (*fsize && *fsize != n)) | |
| 576 | + return -1; | |
| 577 | + *fsize = n; | |
| 578 | + return num + 1; | |
| 579 | + } | |
| 580 | + else if ((type->t & VT_BTYPE) == VT_STRUCT) { | |
| 581 | + int is_struct = 0; // rather than union | |
| 582 | + Sym *field; | |
| 583 | + for (field = type->ref->next; field; field = field->next) | |
| 584 | + if (field->c) { | |
| 585 | + is_struct = 1; | |
| 586 | + break; | |
| 587 | + } | |
| 588 | + if (is_struct) { | |
| 589 | + int num0 = num; | |
| 590 | + for (field = type->ref->next; field; field = field->next) { | |
| 591 | + if (field->c != (num - num0) * *fsize) | |
| 592 | + return -1; | |
| 593 | + num = arm64_hfa_aux(&field->type, fsize, num); | |
| 594 | + if (num == -1) | |
| 595 | + return -1; | |
| 596 | + } | |
| 597 | + if (type->ref->c != (num - num0) * *fsize) | |
| 598 | + return -1; | |
| 599 | + return num; | |
| 600 | + } | |
| 601 | + else { // union | |
| 602 | + int num0 = num; | |
| 603 | + for (field = type->ref->next; field; field = field->next) { | |
| 604 | + int num1 = arm64_hfa_aux(&field->type, fsize, num0); | |
| 605 | + if (num1 == -1) | |
| 606 | + return -1; | |
| 607 | + num = num1 < num ? num : num1; | |
| 608 | + } | |
| 609 | + if (type->ref->c != (num - num0) * *fsize) | |
| 610 | + return -1; | |
| 611 | + return num; | |
| 612 | + } | |
| 613 | + } | |
| 614 | + else if (type->t & VT_ARRAY) { | |
| 615 | + int num1; | |
| 616 | + if (!type->ref->c) | |
| 617 | + return num; | |
| 618 | + num1 = arm64_hfa_aux(&type->ref->type, fsize, num); | |
| 619 | + if (num1 == -1 || (num1 != num && type->ref->c > 4)) | |
| 620 | + return -1; | |
| 621 | + num1 = num + type->ref->c * (num1 - num); | |
| 622 | + if (num1 > 4) | |
| 623 | + return -1; | |
| 624 | + return num1; | |
| 625 | + } | |
| 626 | + return -1; | |
| 627 | +} | |
| 628 | + | |
| 629 | +static int arm64_hfa(CType *type, int *fsize) | |
| 630 | +{ | |
| 631 | + if ((type->t & VT_BTYPE) == VT_STRUCT || (type->t & VT_ARRAY)) { | |
| 632 | + int sz = 0; | |
| 633 | + int n = arm64_hfa_aux(type, &sz, 0); | |
| 634 | + if (0 < n && n <= 4) { | |
| 635 | + if (fsize) | |
| 636 | + *fsize = sz; | |
| 637 | + return n; | |
| 638 | + } | |
| 639 | + } | |
| 640 | + return 0; | |
| 641 | +} | |
| 642 | + | |
| 643 | +static unsigned long arm64_pcs_aux(int n, CType **type, unsigned long *a) | |
| 644 | +{ | |
| 645 | + int nx = 0; // next integer register | |
| 646 | + int nv = 0; // next vector register | |
| 647 | + unsigned long ns = 32; // next stack offset | |
| 648 | + int i; | |
| 649 | + | |
| 650 | + for (i = 0; i < n; i++) { | |
| 651 | + int hfa = arm64_hfa(type[i], 0); | |
| 652 | + int size, align; | |
| 653 | + | |
| 654 | + if ((type[i]->t & VT_ARRAY) || | |
| 655 | + (type[i]->t & VT_BTYPE) == VT_FUNC) | |
| 656 | + size = align = 8; | |
| 657 | + else | |
| 658 | + size = type_size(type[i], &align); | |
| 659 | + | |
| 660 | + if (hfa) | |
| 661 | + // B.2 | |
| 662 | + ; | |
| 663 | + else if (size > 16) { | |
| 664 | + // B.3: replace with pointer | |
| 665 | + if (nx < 8) | |
| 666 | + a[i] = nx++ << 1 | 1; | |
| 667 | + else { | |
| 668 | + ns = (ns + 7) & ~7; | |
| 669 | + a[i] = ns | 1; | |
| 670 | + ns += 8; | |
| 671 | + } | |
| 672 | + continue; | |
| 673 | + } | |
| 674 | + else if ((type[i]->t & VT_BTYPE) == VT_STRUCT) | |
| 675 | + // B.4 | |
| 676 | + size = (size + 7) & ~7; | |
| 677 | + | |
| 678 | + // C.1 | |
| 679 | + if (is_float(type[i]->t) && nv < 8) { | |
| 680 | + a[i] = 16 + (nv++ << 1); | |
| 681 | + continue; | |
| 682 | + } | |
| 683 | + | |
| 684 | + // C.2 | |
| 685 | + if (hfa && nv + hfa <= 8) { | |
| 686 | + a[i] = 16 + (nv << 1); | |
| 687 | + nv += hfa; | |
| 688 | + continue; | |
| 689 | + } | |
| 690 | + | |
| 691 | + // C.3 | |
| 692 | + if (hfa) { | |
| 693 | + nv = 8; | |
| 694 | + size = (size + 7) & ~7; | |
| 695 | + } | |
| 696 | + | |
| 697 | + // C.4 | |
| 698 | + if (hfa || (type[i]->t & VT_BTYPE) == VT_LDOUBLE) { | |
| 699 | + ns = (ns + 7) & ~7; | |
| 700 | + ns = (ns + align - 1) & -align; | |
| 701 | + } | |
| 702 | + | |
| 703 | + // C.5 | |
| 704 | + if ((type[i]->t & VT_BTYPE) == VT_FLOAT) | |
| 705 | + size = 8; | |
| 706 | + | |
| 707 | + // C.6 | |
| 708 | + if (hfa || is_float(type[i]->t)) { | |
| 709 | + a[i] = ns; | |
| 710 | + ns += size; | |
| 711 | + continue; | |
| 712 | + } | |
| 713 | + | |
| 714 | + // C.7 | |
| 715 | + if ((type[i]->t & VT_BTYPE) != VT_STRUCT && size <= 8 && nx < 8) { | |
| 716 | + a[i] = nx++ << 1; | |
| 717 | + continue; | |
| 718 | + } | |
| 719 | + | |
| 720 | + // C.8 | |
| 721 | + if (align == 16) | |
| 722 | + nx = (nx + 1) & ~1; | |
| 723 | + | |
| 724 | + // C.9 | |
| 725 | + if ((type[i]->t & VT_BTYPE) != VT_STRUCT && size == 16 && nx < 7) { | |
| 726 | + a[i] = nx << 1; | |
| 727 | + nx += 2; | |
| 728 | + continue; | |
| 729 | + } | |
| 730 | + | |
| 731 | + // C.10 | |
| 732 | + if ((type[i]->t & VT_BTYPE) == VT_STRUCT && size <= (8 - nx) * 8) { | |
| 733 | + a[i] = nx << 1; | |
| 734 | + nx += (size + 7) >> 3; | |
| 735 | + continue; | |
| 736 | + } | |
| 737 | + | |
| 738 | + // C.11 | |
| 739 | + nx = 8; | |
| 740 | + | |
| 741 | + // C.12 | |
| 742 | + ns = (ns + 7) & ~7; | |
| 743 | + ns = (ns + align - 1) & -align; | |
| 744 | + | |
| 745 | + // C.13 | |
| 746 | + if ((type[i]->t & VT_BTYPE) == VT_STRUCT) { | |
| 747 | + a[i] = ns; | |
| 748 | + ns += size; | |
| 749 | + continue; | |
| 750 | + } | |
| 751 | + | |
| 752 | + // C.14 | |
| 753 | + if (size < 8) | |
| 754 | + size = 8; | |
| 755 | + | |
| 756 | + // C.15 | |
| 757 | + a[i] = ns; | |
| 758 | + ns += size; | |
| 759 | + } | |
| 760 | + | |
| 761 | + return ns - 32; | |
| 762 | +} | |
| 763 | + | |
| 764 | +static unsigned long arm64_pcs(int n, CType **type, unsigned long *a) | |
| 765 | +{ | |
| 766 | + unsigned long stack; | |
| 767 | + | |
| 768 | + // Return type: | |
| 769 | + if ((type[0]->t & VT_BTYPE) == VT_VOID) | |
| 770 | + a[0] = -1; | |
| 771 | + else { | |
| 772 | + arm64_pcs_aux(1, type, a); | |
| 773 | + assert(a[0] == 0 || a[0] == 1 || a[0] == 16); | |
| 774 | + } | |
| 775 | + | |
| 776 | + // Argument types: | |
| 777 | + stack = arm64_pcs_aux(n, type + 1, a + 1); | |
| 778 | + | |
| 779 | + if (0) { | |
| 780 | + int i; | |
| 781 | + for (i = 0; i <= n; i++) { | |
| 782 | + if (!i) | |
| 783 | + printf("arm64_pcs return: "); | |
| 784 | + else | |
| 785 | + printf("arm64_pcs arg %d: ", i); | |
| 786 | + if (a[i] == (unsigned long)-1) | |
| 787 | + printf("void\n"); | |
| 788 | + else if (a[i] == 1 && !i) | |
| 789 | + printf("X8 pointer\n"); | |
| 790 | + else if (a[i] < 16) | |
| 791 | + printf("X%lu%s\n", a[i] / 2, a[i] & 1 ? " pointer" : ""); | |
| 792 | + else if (a[i] < 32) | |
| 793 | + printf("V%lu\n", a[i] / 2 - 8); | |
| 794 | + else | |
| 795 | + printf("stack %lu%s\n", | |
| 796 | + (a[i] - 32) & ~1, a[i] & 1 ? " pointer" : ""); | |
| 797 | + } | |
| 798 | + } | |
| 799 | + | |
| 800 | + return stack; | |
| 801 | +} | |
| 802 | + | |
| 803 | +ST_FUNC void gfunc_call(int nb_args) | |
| 804 | +{ | |
| 805 | + CType *return_type; | |
| 806 | + CType **t; | |
| 807 | + unsigned long *a, *a1; | |
| 808 | + unsigned long stack; | |
| 809 | + int i; | |
| 810 | + | |
| 811 | + return_type = &vtop[-nb_args].type.ref->type; | |
| 812 | + if ((return_type->t & VT_BTYPE) == VT_STRUCT) | |
| 813 | + --nb_args; | |
| 814 | + | |
| 815 | + t = tcc_malloc((nb_args + 1) * sizeof(*t)); | |
| 816 | + a = tcc_malloc((nb_args + 1) * sizeof(*a)); | |
| 817 | + a1 = tcc_malloc((nb_args + 1) * sizeof(*a1)); | |
| 818 | + | |
| 819 | + t[0] = return_type; | |
| 820 | + for (i = 0; i < nb_args; i++) | |
| 821 | + t[nb_args - i] = &vtop[-i].type; | |
| 822 | + | |
| 823 | + stack = arm64_pcs(nb_args, t, a); | |
| 824 | + | |
| 825 | + // Allocate space for structs replaced by pointer: | |
| 826 | + for (i = nb_args; i; i--) | |
| 827 | + if (a[i] & 1) { | |
| 828 | + SValue *arg = &vtop[i - nb_args]; | |
| 829 | + int align, size = type_size(&arg->type, &align); | |
| 830 | + assert((arg->type.t & VT_BTYPE) == VT_STRUCT); | |
| 831 | + stack = (stack + align - 1) & -align; | |
| 832 | + a1[i] = stack; | |
| 833 | + stack += size; | |
| 834 | + } | |
| 835 | + | |
| 836 | + stack = (stack + 15) >> 4 << 4; | |
| 837 | + | |
| 838 | + assert(stack < 0x1000); | |
| 839 | + if (stack) | |
| 840 | + o(0xd10003ff | stack << 10); // sub sp,sp,#(n) | |
| 841 | + | |
| 842 | + // First pass: set all values on stack | |
| 843 | + for (i = nb_args; i; i--) { | |
| 844 | + vpushv(vtop - nb_args + i); | |
| 845 | + | |
| 846 | + if (a[i] & 1) { | |
| 847 | + // struct replaced by pointer | |
| 848 | + int r = get_reg(RC_INT); | |
| 849 | + gen_stack_addr(intr(r), a1[i]); | |
| 850 | + vset(&vtop->type, r | VT_LVAL, 0); | |
| 851 | + vswap(); | |
| 852 | + vstore(); | |
| 853 | + if (a[i] >= 32) { | |
| 854 | + // pointer on stack | |
| 855 | + r = get_reg(RC_INT); | |
| 856 | + gen_stack_addr(intr(r), a1[i]); | |
| 857 | + gen_store(3, intr(r), 31, (a[i] - 32) >> 1 << 1); | |
| 858 | + } | |
| 859 | + } | |
| 860 | + else if (a[i] >= 32) { | |
| 861 | + // value on stack | |
| 862 | + if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { | |
| 863 | + int r = get_reg(RC_INT); | |
| 864 | + gen_stack_addr(intr(r), a[i] - 32); | |
| 865 | + vset(&vtop->type, r | VT_LVAL, 0); | |
| 866 | + vswap(); | |
| 867 | + vstore(); | |
| 868 | + } | |
| 869 | + else if (is_float(vtop->type.t)) { | |
| 870 | + gv(RC_FLOAT); | |
| 871 | + gen_fstore(arm64_type_size(vtop[0].type.t), | |
| 872 | + fltr(vtop[0].r), 31, a[i] - 32); | |
| 873 | + } | |
| 874 | + else { | |
| 875 | + gv(RC_INT); | |
| 876 | + gen_store(arm64_type_size(vtop[0].type.t), | |
| 877 | + intr(vtop[0].r), 31, a[i] - 32); | |
| 878 | + } | |
| 879 | + } | |
| 880 | + | |
| 881 | + --vtop; | |
| 882 | + } | |
| 883 | + | |
| 884 | + // Second pass: assign values to registers | |
| 885 | + for (i = nb_args; i; i--, vtop--) { | |
| 886 | + if (a[i] < 16 && !(a[i] & 1)) { | |
| 887 | + // value in general-purpose registers | |
| 888 | + if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { | |
| 889 | + int align, size = type_size(&vtop->type, &align); | |
| 890 | + vtop->type.t = VT_PTR; | |
| 891 | + gaddrof(); | |
| 892 | + gv(RC_R(a[i] / 2)); | |
| 893 | + gen_sload(a[i] / 2, size); | |
| 894 | + } | |
| 895 | + else | |
| 896 | + gv(RC_R(a[i] / 2)); | |
| 897 | + } | |
| 898 | + else if (a[i] < 16) | |
| 899 | + // struct replaced by pointer in register | |
| 900 | + gen_stack_addr(a[i] / 2, a1[i]); | |
| 901 | + else if (a[i] < 32) { | |
| 902 | + // value in floating-point registers | |
| 903 | + if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { | |
| 904 | + int j, sz, n = arm64_hfa(&vtop->type, &sz); | |
| 905 | + vtop->type.t = VT_PTR; | |
| 906 | + gaddrof(); | |
| 907 | + gv(RC_R30); | |
| 908 | + for (j = 0; j < n; j++) | |
| 909 | + o(0x3d4003c0 | | |
| 910 | + (sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 | | |
| 911 | + (a[i] / 2 - 8 + j) | | |
| 912 | + j << 10); // ldr ([sdq])(*),[x30,#(j * sz)] | |
| 913 | + } | |
| 914 | + else | |
| 915 | + gv(RC_F(a[i] / 2 - 8)); | |
| 916 | + } | |
| 917 | + } | |
| 918 | + | |
| 919 | + if ((return_type->t & VT_BTYPE) == VT_STRUCT) { | |
| 920 | + if (a[0] == 1) { | |
| 921 | + // indirect return: set x8 and discard the stack value | |
| 922 | + gv(RC_R(8)); | |
| 923 | + --vtop; | |
| 924 | + } | |
| 925 | + else | |
| 926 | + // return in registers: keep the address for after the call | |
| 927 | + vswap(); | |
| 928 | + } | |
| 929 | + | |
| 930 | + save_regs(0); | |
| 931 | + arm64_gen_bl_or_b(0); | |
| 932 | + --vtop; | |
| 933 | + if (stack) | |
| 934 | + o(0x910003ff | stack << 10); // add sp,sp,#(n) | |
| 935 | + | |
| 936 | + { | |
| 937 | + int rt = return_type->t; | |
| 938 | + int bt = rt & VT_BTYPE; | |
| 939 | + if (bt == VT_BYTE || bt == VT_SHORT) | |
| 940 | + // Promote small integers: | |
| 941 | + o(0x13001c00 | (bt == VT_SHORT) << 13 | | |
| 942 | + !!(rt & VT_UNSIGNED) << 30); // [su]xt[bh] w0,w0 | |
| 943 | + else if (bt == VT_STRUCT && !(a[0] & 1)) { | |
| 944 | + // A struct was returned in registers, so write it out: | |
| 945 | + gv(RC_R(8)); | |
| 946 | + --vtop; | |
| 947 | + if (a[0] == 0) { | |
| 948 | + int align, size = type_size(return_type, &align); | |
| 949 | + assert(size <= 16); | |
| 950 | + if (size > 8) | |
| 951 | + o(0xa9000500); // stp x0,x1,[x8] | |
| 952 | + else if (size) | |
| 953 | + gen_store(size > 4 ? 3 : size > 2 ? 2 : size > 1, | |
| 954 | + 0, 8, 0); | |
| 955 | + | |
| 956 | + } | |
| 957 | + else if (a[0] == 16) { | |
| 958 | + int j, sz, n = arm64_hfa(return_type, &sz); | |
| 959 | + for (j = 0; j < n; j++) | |
| 960 | + o(0x3d000100 | | |
| 961 | + (sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 | | |
| 962 | + (a[i] / 2 - 8 + j) | | |
| 963 | + j << 10); // str ([sdq])(*),[x8,#(j * sz)] | |
| 964 | + } | |
| 965 | + } | |
| 966 | + } | |
| 967 | + | |
| 968 | + tcc_free(a1); | |
| 969 | + tcc_free(a); | |
| 970 | + tcc_free(t); | |
| 971 | +} | |
| 972 | + | |
| 973 | +static unsigned long arm64_func_va_list_stack; | |
| 974 | +static int arm64_func_va_list_gr_offs; | |
| 975 | +static int arm64_func_va_list_vr_offs; | |
| 976 | +static int arm64_func_sub_sp_offset; | |
| 977 | + | |
| 978 | +ST_FUNC void gfunc_prolog(CType *func_type) | |
| 979 | +{ | |
| 980 | + int n = 0; | |
| 981 | + int i = 0; | |
| 982 | + Sym *sym; | |
| 983 | + CType **t; | |
| 984 | + unsigned long *a; | |
| 985 | + | |
| 986 | + // Why doesn't the caller (gen_function) set func_vt? | |
| 987 | + func_vt = func_type->ref->type; | |
| 988 | + func_vc = 144; // offset of where x8 is stored | |
| 989 | + | |
| 990 | + for (sym = func_type->ref; sym; sym = sym->next) | |
| 991 | + ++n; | |
| 992 | + t = tcc_malloc(n * sizeof(*t)); | |
| 993 | + a = tcc_malloc(n * sizeof(*a)); | |
| 994 | + | |
| 995 | + for (sym = func_type->ref; sym; sym = sym->next) | |
| 996 | + t[i++] = &sym->type; | |
| 997 | + | |
| 998 | + arm64_func_va_list_stack = arm64_pcs(n - 1, t, a); | |
| 999 | + | |
| 1000 | + o(0xa9b27bfd); // stp x29,x30,[sp,#-224]! | |
| 1001 | + o(0xad0087e0); // stp q0,q1,[sp,#16] | |
| 1002 | + o(0xad018fe2); // stp q2,q3,[sp,#48] | |
| 1003 | + o(0xad0297e4); // stp q4,q5,[sp,#80] | |
| 1004 | + o(0xad039fe6); // stp q6,q7,[sp,#112] | |
| 1005 | + o(0xa90923e8); // stp x8,x8,[sp,#144] | |
| 1006 | + o(0xa90a07e0); // stp x0,x1,[sp,#160] | |
| 1007 | + o(0xa90b0fe2); // stp x2,x3,[sp,#176] | |
| 1008 | + o(0xa90c17e4); // stp x4,x5,[sp,#192] | |
| 1009 | + o(0xa90d1fe6); // stp x6,x7,[sp,#208] | |
| 1010 | + | |
| 1011 | + arm64_func_va_list_gr_offs = -64; | |
| 1012 | + arm64_func_va_list_vr_offs = -128; | |
| 1013 | + | |
| 1014 | + for (i = 1, sym = func_type->ref->next; sym; i++, sym = sym->next) { | |
| 1015 | + int off = (a[i] < 16 ? 160 + a[i] / 2 * 8 : | |
| 1016 | + a[i] < 32 ? 16 + (a[i] - 16) / 2 * 16 : | |
| 1017 | + 224 + ((a[i] - 32) >> 1 << 1)); | |
| 1018 | + sym_push(sym->v & ~SYM_FIELD, &sym->type, | |
| 1019 | + (a[i] & 1 ? VT_LLOCAL : VT_LOCAL) | lvalue_type(sym->type.t), | |
| 1020 | + off); | |
| 1021 | + | |
| 1022 | + if (a[i] < 16) { | |
| 1023 | + int align, size = type_size(&sym->type, &align); | |
| 1024 | + arm64_func_va_list_gr_offs = (a[i] / 2 - 7 + | |
| 1025 | + (!(a[i] & 1) && size > 8)) * 8; | |
| 1026 | + } | |
| 1027 | + else if (a[i] < 32) { | |
| 1028 | + int hfa = arm64_hfa(&sym->type, 0); | |
| 1029 | + arm64_func_va_list_vr_offs = (a[i] / 2 - 16 + | |
| 1030 | + (hfa ? hfa : 1)) * 16; | |
| 1031 | + } | |
| 1032 | + | |
| 1033 | + // HFAs of float and double need to be written differently: | |
| 1034 | + if (16 <= a[i] && a[i] < 32 && (sym->type.t & VT_BTYPE) == VT_STRUCT) { | |
| 1035 | + int j, sz, k = arm64_hfa(&sym->type, &sz); | |
| 1036 | + if (sz < 16) | |
| 1037 | + for (j = 0; j < k; j++) { | |
| 1038 | + o(0x3d0003e0 | -(sz & 8) << 27 | (sz & 4) << 29 | | |
| 1039 | + ((a[i] - 16) / 2 + j) | (off / sz + j) << 10); | |
| 1040 | + // str ([sdq])(*),[sp,#(j * sz)] | |
| 1041 | + } | |
| 1042 | + } | |
| 1043 | + } | |
| 1044 | + | |
| 1045 | + tcc_free(a); | |
| 1046 | + tcc_free(t); | |
| 1047 | + | |
| 1048 | + o(0x910003fd); // mov x29,sp | |
| 1049 | + arm64_func_sub_sp_offset = ind; | |
| 1050 | + // In gfunc_epilog these will be replaced with code to decrement SP: | |
| 1051 | + o(0xd503201f); // nop | |
| 1052 | + o(0xd503201f); // nop | |
| 1053 | + loc = 0; | |
| 1054 | +} | |
| 1055 | + | |
| 1056 | +ST_FUNC void gen_va_start(void) | |
| 1057 | +{ | |
| 1058 | + int r; | |
| 1059 | + --vtop; // we don't need the "arg" | |
| 1060 | + gaddrof(); | |
| 1061 | + r = intr(gv(RC_INT)); | |
| 1062 | + | |
| 1063 | + if (arm64_func_va_list_stack) { | |
| 1064 | + //xx could use add (immediate) here | |
| 1065 | + arm64_movimm(30, arm64_func_va_list_stack + 224); | |
| 1066 | + o(0x8b1e03be); // add x30,x29,x30 | |
| 1067 | + } | |
| 1068 | + else | |
| 1069 | + o(0x910383be); // add x30,x29,#224 | |
| 1070 | + o(0xf900001e | r << 5); // str x30,[x(r)] | |
| 1071 | + | |
| 1072 | + if (arm64_func_va_list_gr_offs) { | |
| 1073 | + if (arm64_func_va_list_stack) | |
| 1074 | + o(0x910383be); // add x30,x29,#224 | |
| 1075 | + o(0xf900041e | r << 5); // str x30,[x(r),#8] | |
| 1076 | + } | |
| 1077 | + | |
| 1078 | + if (arm64_func_va_list_vr_offs) { | |
| 1079 | + o(0x910243be); // add x30,x29,#144 | |
| 1080 | + o(0xf900081e | r << 5); // str x30,[x(r),#16] | |
| 1081 | + } | |
| 1082 | + | |
| 1083 | + arm64_movimm(30, arm64_func_va_list_gr_offs); | |
| 1084 | + o(0xb900181e | r << 5); // str w30,[x(r),#24] | |
| 1085 | + | |
| 1086 | + arm64_movimm(30, arm64_func_va_list_vr_offs); | |
| 1087 | + o(0xb9001c1e | r << 5); // str w30,[x(r),#28] | |
| 1088 | + | |
| 1089 | + --vtop; | |
| 1090 | +} | |
| 1091 | + | |
| 1092 | +ST_FUNC void gen_va_arg(CType *t) | |
| 1093 | +{ | |
| 1094 | + int align, size = type_size(t, &align); | |
| 1095 | + int fsize, hfa = arm64_hfa(t, &fsize); | |
| 1096 | + int r0, r1; | |
| 1097 | + | |
| 1098 | + if (is_float(t->t)) { | |
| 1099 | + hfa = 1; | |
| 1100 | + fsize = size; | |
| 1101 | + } | |
| 1102 | + | |
| 1103 | + gaddrof(); | |
| 1104 | + r0 = intr(gv(RC_INT)); | |
| 1105 | + r1 = get_reg(RC_INT); | |
| 1106 | + vtop[0].r = r1 | lvalue_type(t->t); | |
| 1107 | + r1 = intr(r1); | |
| 1108 | + | |
| 1109 | + if (!hfa) { | |
| 1110 | + uint32_t n = size > 16 ? 8 : (size + 7) & -8; | |
| 1111 | + if (size == 16 && align == 16) | |
| 1112 | + tcc_error("va_arg(ap, __uint128_t) unimplemented"); | |
| 1113 | + o(0xb940181e | r0 << 5); // ldr w30,[x(r0),#24] // __gr_offs | |
| 1114 | + o(0x310003c0 | r1 | n << 10); // adds w(r1),w30,#(n) | |
| 1115 | + o(0x540000ad); // b.le .+20 | |
| 1116 | + o(0xf9400000 | r1 | r0 << 5); // ldr x(r1),[x(r0)] // __stack | |
| 1117 | + o(0x9100001e | r1 << 5 | n << 10); // add x30,x(r1),#(n) | |
| 1118 | + o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack | |
| 1119 | + o(0x14000004); // b .+16 | |
| 1120 | + o(0xb9001800 | r1 | r0 << 5); // str w(r1),[x(r0),#24] // __gr_offs | |
| 1121 | + o(0xf9400400 | r1 | r0 << 5); // ldr x(r1),[x(r0),#8] // __gr_top | |
| 1122 | + o(0x8b3ec000 | r1 | r1 << 5); // add x(r1),x(r1),w30,sxtw | |
| 1123 | + if (size > 16) | |
| 1124 | + o(0xf9400000 | r1 | r1 << 5); // ldr x(r1),[x(r1)] | |
| 1125 | + } | |
| 1126 | + else { | |
| 1127 | + uint32_t rsz = hfa << 4; | |
| 1128 | + uint32_t ssz = (size + 7) & -(uint32_t)8; | |
| 1129 | + uint32_t b1; | |
| 1130 | + if (hfa > 1 && fsize < 16) | |
| 1131 | + // We may need to change the layout of this HFA | |
| 1132 | + tcc_error("va_arg(ap, HFA) unimplemented"); | |
| 1133 | + o(0xb9401c1e | r0 << 5); // ldr w30,[x(r0),#28] // __vr_offs | |
| 1134 | + o(0x310003c0 | r1 | rsz << 10); // adds w(r1),w30,#(rsz) | |
| 1135 | + b1 = ind; o(0x5400000d); // b.le lab1 | |
| 1136 | + o(0xf9400000 | r1 | r0 << 5); // ldr x(r1),[x(r0)] // __stack | |
| 1137 | + if (fsize == 16) { | |
| 1138 | + o(0x91003c00 | r1 | r1 << 5); // add x(r1),x(r1),#15 | |
| 1139 | + o(0x927cec00 | r1 | r1 << 5); // and x(r1),x(r1),#-16 | |
| 1140 | + } | |
| 1141 | + o(0x9100001e | r1 << 5 | ssz << 10); // add x30,x(r1),#(ssz) | |
| 1142 | + o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack | |
| 1143 | + o(0x14000004); // b .+16 | |
| 1144 | + // lab1: | |
| 1145 | + *(uint32_t *)(cur_text_section->data + b1) = | |
| 1146 | + (0x5400000d | (ind - b1) << 3); | |
| 1147 | + o(0xb9001c00 | r1 | r0 << 5); // str w(r1),[x(r0),#28] // __vr_offs | |
| 1148 | + o(0xf9400800 | r1 | r0 << 5); // ldr x(r1),[x(r0),#16] // __vr_top | |
| 1149 | + o(0x8b3ec000 | r1 | r1 << 5); // add x(r1),x(r1),w30,sxtw | |
| 1150 | + } | |
| 1151 | +} | |
| 1152 | + | |
| 1153 | +ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align) | |
| 1154 | +{ | |
| 1155 | + return 0; | |
| 1156 | +} | |
| 1157 | + | |
| 1158 | +ST_FUNC void greturn(void) | |
| 1159 | +{ | |
| 1160 | + CType *t = &func_vt; | |
| 1161 | + unsigned long a; | |
| 1162 | + | |
| 1163 | + arm64_pcs(0, &t, &a); | |
| 1164 | + switch (a) { | |
| 1165 | + case -1: | |
| 1166 | + break; | |
| 1167 | + case 0: | |
| 1168 | + if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { | |
| 1169 | + int align, size = type_size(&func_vt, &align); | |
| 1170 | + gaddrof(); | |
| 1171 | + gv(RC_R(0)); | |
| 1172 | + gen_sload(0, size); | |
| 1173 | + } | |
| 1174 | + else | |
| 1175 | + gv(RC_IRET); | |
| 1176 | + break; | |
| 1177 | + case 1: { | |
| 1178 | + CType type = func_vt; | |
| 1179 | + mk_pointer(&type); | |
| 1180 | + vset(&type, VT_LOCAL | VT_LVAL, func_vc); | |
| 1181 | + indir(); | |
| 1182 | + vswap(); | |
| 1183 | + vstore(); | |
| 1184 | + break; | |
| 1185 | + } | |
| 1186 | + case 16: | |
| 1187 | + if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { | |
| 1188 | + int j, sz, n = arm64_hfa(&vtop->type, &sz); | |
| 1189 | + gaddrof(); | |
| 1190 | + gv(RC_R(0)); | |
| 1191 | + for (j = 0; j < n; j++) | |
| 1192 | + o(0x3d400000 | | |
| 1193 | + (sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 | | |
| 1194 | + j | j << 10); // ldr ([sdq])(*),[x0,#(j * sz)] | |
| 1195 | + } | |
| 1196 | + else | |
| 1197 | + gv(RC_FRET); | |
| 1198 | + break; | |
| 1199 | + default: | |
| 1200 | + assert(0); | |
| 1201 | + } | |
| 1202 | +} | |
| 1203 | + | |
| 1204 | +ST_FUNC void gfunc_epilog(void) | |
| 1205 | +{ | |
| 1206 | + if (loc) { | |
| 1207 | + // Insert instructions to subtract size of stack frame from SP. | |
| 1208 | + uint32_t *ptr = | |
| 1209 | + (uint32_t *)(cur_text_section->data + arm64_func_sub_sp_offset); | |
| 1210 | + uint64_t diff = (-loc + 15) & ~15; | |
| 1211 | + if (!(diff >> 24)) { | |
| 1212 | + if (diff & 0xfff) // sub sp,sp,#(diff & 0xfff) | |
| 1213 | + ptr[0] = 0xd10003ff | (diff & 0xfff) << 10; | |
| 1214 | + if (diff >> 12) // sub sp,sp,#(diff >> 12),lsl #12 | |
| 1215 | + ptr[1] = 0xd14003ff | (diff >> 12) << 10; | |
| 1216 | + } | |
| 1217 | + else { | |
| 1218 | + // In this case we may subtract more than necessary, | |
| 1219 | + // but always less than 17/16 of what we were aiming for. | |
| 1220 | + int i = 0; | |
| 1221 | + int j = 0; | |
| 1222 | + while (diff >> 20) { | |
| 1223 | + diff = (diff + 0xffff) >> 16; | |
| 1224 | + ++i; | |
| 1225 | + } | |
| 1226 | + while (diff >> 16) { | |
| 1227 | + diff = (diff + 1) >> 1; | |
| 1228 | + ++j; | |
| 1229 | + } | |
| 1230 | + ptr[0] = 0xd2800010 | diff << 5 | i << 21; | |
| 1231 | + // mov x16,#(diff),lsl #(16 * i) | |
| 1232 | + ptr[1] = 0xcb3063ff | j << 10; | |
| 1233 | + // sub sp,sp,x16,lsl #(j) | |
| 1234 | + } | |
| 1235 | + } | |
| 1236 | + o(0x910003bf); // mov sp,x29 | |
| 1237 | + o(0xa8ce7bfd); // ldp x29,x30,[sp],#224 | |
| 1238 | + | |
| 1239 | + o(0xd65f03c0); // ret | |
| 1240 | +} | |
| 1241 | + | |
| 1242 | +// Generate forward branch to label: | |
| 1243 | +ST_FUNC int gjmp(int t) | |
| 1244 | +{ | |
| 1245 | + int r = ind; | |
| 1246 | + o(t); | |
| 1247 | + return r; | |
| 1248 | +} | |
| 1249 | + | |
| 1250 | +// Generate branch to known address: | |
| 1251 | +ST_FUNC void gjmp_addr(int a) | |
| 1252 | +{ | |
| 1253 | + assert(a - ind + 0x8000000 < 0x10000000); | |
| 1254 | + o(0x14000000 | ((a - ind) >> 2 & 0x3ffffff)); | |
| 1255 | +} | |
| 1256 | + | |
| 1257 | +ST_FUNC int gtst(int inv, int t) | |
| 1258 | +{ | |
| 1259 | + int bt = vtop->type.t & VT_BTYPE; | |
| 1260 | + if (bt == VT_LDOUBLE) { | |
| 1261 | + int a, b, f = fltr(gv(RC_FLOAT)); | |
| 1262 | + a = get_reg(RC_INT); | |
| 1263 | + vpushi(0); | |
| 1264 | + vtop[0].r = a; | |
| 1265 | + b = get_reg(RC_INT); | |
| 1266 | + a = intr(a); | |
| 1267 | + b = intr(b); | |
| 1268 | + o(0x4e083c00 | a | f << 5); // mov x(a),v(f).d[0] | |
| 1269 | + o(0x4e183c00 | b | f << 5); // mov x(b),v(f).d[1] | |
| 1270 | + o(0xaa000400 | a | a << 5 | b << 16); // orr x(a),x(a),x(b),lsl #1 | |
| 1271 | + o(0xb4000040 | a | !!inv << 24); // cbz/cbnz x(a),.+8 | |
| 1272 | + --vtop; | |
| 1273 | + } | |
| 1274 | + else if (bt == VT_FLOAT || bt == VT_DOUBLE) { | |
| 1275 | + int a = fltr(gv(RC_FLOAT)); | |
| 1276 | + o(0x1e202008 | a << 5 | (bt != VT_FLOAT) << 22); // fcmp | |
| 1277 | + o(0x54000040 | !!inv); // b.eq/b.ne .+8 | |
| 1278 | + } | |
| 1279 | + else { | |
| 1280 | + int ll = (bt == VT_PTR || bt == VT_LLONG); | |
| 1281 | + int a = intr(gv(RC_INT)); | |
| 1282 | + o(0x34000040 | a | !!inv << 24 | ll << 31); // cbz/cbnz wA,.+8 | |
| 1283 | + } | |
| 1284 | + --vtop; | |
| 1285 | + return gjmp(t); | |
| 1286 | +} | |
| 1287 | + | |
| 1288 | +static void arm64_gen_opil(int op, int l) | |
| 1289 | +{ | |
| 1290 | + int x, a, b; | |
| 1291 | + gv2(RC_INT, RC_INT); | |
| 1292 | + assert(vtop[-1].r < VT_CONST && vtop[0].r < VT_CONST); | |
| 1293 | + a = intr(vtop[-1].r); | |
| 1294 | + b = intr(vtop[0].r); | |
| 1295 | + vtop -= 2; | |
| 1296 | + x = get_reg(RC_INT); | |
| 1297 | + ++vtop; | |
| 1298 | + vtop[0].r = x; | |
| 1299 | + x = intr(x); | |
| 1300 | + | |
| 1301 | + switch (op) { | |
| 1302 | + case '%': | |
| 1303 | + // Use x30 for quotient: | |
| 1304 | + o(0x1ac00c00 | l << 31 | 30 | a << 5 | b << 16); // sdiv | |
| 1305 | + o(0x1b008000 | l << 31 | x | 30 << 5 | b << 16 | a << 10); // msub | |
| 1306 | + break; | |
| 1307 | + case '&': | |
| 1308 | + o(0x0a000000 | l << 31 | x | a << 5 | b << 16); // and | |
| 1309 | + break; | |
| 1310 | + case '*': | |
| 1311 | + o(0x1b007c00 | l << 31 | x | a << 5 | b << 16); // mul | |
| 1312 | + break; | |
| 1313 | + case '+': | |
| 1314 | + o(0x0b000000 | l << 31 | x | a << 5 | b << 16); // add | |
| 1315 | + break; | |
| 1316 | + case '-': | |
| 1317 | + o(0x4b000000 | l << 31 | x | a << 5 | b << 16); // sub | |
| 1318 | + break; | |
| 1319 | + case '/': | |
| 1320 | + o(0x1ac00c00 | l << 31 | x | a << 5 | b << 16); // sdiv | |
| 1321 | + break; | |
| 1322 | + case '^': | |
| 1323 | + o(0x4a000000 | l << 31 | x | a << 5 | b << 16); // eor | |
| 1324 | + break; | |
| 1325 | + case '|': | |
| 1326 | + o(0x2a000000 | l << 31 | x | a << 5 | b << 16); // orr | |
| 1327 | + break; | |
| 1328 | + case TOK_EQ: | |
| 1329 | + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp | |
| 1330 | + o(0x1a9f17e0 | x); // cset wA,eq | |
| 1331 | + break; | |
| 1332 | + case TOK_GE: | |
| 1333 | + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp | |
| 1334 | + o(0x1a9fb7e0 | x); // cset wA,ge | |
| 1335 | + break; | |
| 1336 | + case TOK_GT: | |
| 1337 | + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp | |
| 1338 | + o(0x1a9fd7e0 | x); // cset wA,gt | |
| 1339 | + break; | |
| 1340 | + case TOK_LE: | |
| 1341 | + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp | |
| 1342 | + o(0x1a9fc7e0 | x); // cset wA,le | |
| 1343 | + break; | |
| 1344 | + case TOK_LT: | |
| 1345 | + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp | |
| 1346 | + o(0x1a9fa7e0 | x); // cset wA,lt | |
| 1347 | + break; | |
| 1348 | + case TOK_NE: | |
| 1349 | + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp | |
| 1350 | + o(0x1a9f07e0 | x); // cset wA,ne | |
| 1351 | + break; | |
| 1352 | + case TOK_SAR: | |
| 1353 | + o(0x1ac02800 | l << 31 | x | a << 5 | b << 16); // asr | |
| 1354 | + break; | |
| 1355 | + case TOK_SHL: | |
| 1356 | + o(0x1ac02000 | l << 31 | x | a << 5 | b << 16); // lsl | |
| 1357 | + break; | |
| 1358 | + case TOK_SHR: | |
| 1359 | + o(0x1ac02400 | l << 31 | x | a << 5 | b << 16); // lsr | |
| 1360 | + break; | |
| 1361 | + case TOK_UDIV: | |
| 1362 | + case TOK_PDIV: | |
| 1363 | + o(0x1ac00800 | l << 31 | x | a << 5 | b << 16); // udiv | |
| 1364 | + break; | |
| 1365 | + case TOK_UGE: | |
| 1366 | + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp | |
| 1367 | + o(0x1a9f37e0 | x); // cset wA,cs | |
| 1368 | + break; | |
| 1369 | + case TOK_UGT: | |
| 1370 | + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp | |
| 1371 | + o(0x1a9f97e0 | x); // cset wA,hi | |
| 1372 | + break; | |
| 1373 | + case TOK_ULT: | |
| 1374 | + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp | |
| 1375 | + o(0x1a9f27e0 | x); // cset wA,cc | |
| 1376 | + break; | |
| 1377 | + case TOK_ULE: | |
| 1378 | + o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp | |
| 1379 | + o(0x1a9f87e0 | x); // cset wA,ls | |
| 1380 | + break; | |
| 1381 | + case TOK_UMOD: | |
| 1382 | + // Use x30 for quotient: | |
| 1383 | + o(0x1ac00800 | l << 31 | 30 | a << 5 | b << 16); // udiv | |
| 1384 | + o(0x1b008000 | l << 31 | x | 30 << 5 | b << 16 | a << 10); // msub | |
| 1385 | + break; | |
| 1386 | + default: | |
| 1387 | + assert(0); | |
| 1388 | + } | |
| 1389 | +} | |
| 1390 | + | |
| 1391 | +ST_FUNC void gen_opi(int op) | |
| 1392 | +{ | |
| 1393 | + arm64_gen_opil(op, 0); | |
| 1394 | +} | |
| 1395 | + | |
| 1396 | +ST_FUNC void gen_opl(int op) | |
| 1397 | +{ | |
| 1398 | + arm64_gen_opil(op, 1); | |
| 1399 | +} | |
| 1400 | + | |
| 1401 | +ST_FUNC void gen_opf(int op) | |
| 1402 | +{ | |
| 1403 | + int x, a, b, dbl; | |
| 1404 | + | |
| 1405 | + if (vtop[0].type.t == VT_LDOUBLE) { | |
| 1406 | + CType type = vtop[0].type; | |
| 1407 | + int func = 0; | |
| 1408 | + int cond = -1; | |
| 1409 | + switch (op) { | |
| 1410 | + case '*': func = TOK___multf3; break; | |
| 1411 | + case '+': func = TOK___addtf3; break; | |
| 1412 | + case '-': func = TOK___subtf3; break; | |
| 1413 | + case '/': func = TOK___divtf3; break; | |
| 1414 | + case TOK_EQ: func = TOK___eqtf2; cond = 1; break; | |
| 1415 | + case TOK_NE: func = TOK___netf2; cond = 0; break; | |
| 1416 | + case TOK_LT: func = TOK___lttf2; cond = 10; break; | |
| 1417 | + case TOK_GE: func = TOK___getf2; cond = 11; break; | |
| 1418 | + case TOK_LE: func = TOK___letf2; cond = 12; break; | |
| 1419 | + case TOK_GT: func = TOK___gttf2; cond = 13; break; | |
| 1420 | + default: assert(0); break; | |
| 1421 | + } | |
| 1422 | + vpush_global_sym(&func_old_type, func); | |
| 1423 | + vrott(3); | |
| 1424 | + gfunc_call(2); | |
| 1425 | + vpushi(0); | |
| 1426 | + vtop->r = cond < 0 ? REG_FRET : REG_IRET; | |
| 1427 | + if (cond < 0) | |
| 1428 | + vtop->type = type; | |
| 1429 | + else { | |
| 1430 | + o(0x7100001f); // cmp w0,#0 | |
| 1431 | + o(0x1a9f07e0 | cond << 12); // cset w0,(cond) | |
| 1432 | + } | |
| 1433 | + return; | |
| 1434 | + } | |
| 1435 | + | |
| 1436 | + dbl = vtop[0].type.t != VT_FLOAT; | |
| 1437 | + gv2(RC_FLOAT, RC_FLOAT); | |
| 1438 | + assert(vtop[-1].r < VT_CONST && vtop[0].r < VT_CONST); | |
| 1439 | + a = fltr(vtop[-1].r); | |
| 1440 | + b = fltr(vtop[0].r); | |
| 1441 | + vtop -= 2; | |
| 1442 | + switch (op) { | |
| 1443 | + case TOK_EQ: case TOK_NE: | |
| 1444 | + case TOK_LT: case TOK_GE: case TOK_LE: case TOK_GT: | |
| 1445 | + x = get_reg(RC_INT); | |
| 1446 | + ++vtop; | |
| 1447 | + vtop[0].r = x; | |
| 1448 | + x = intr(x); | |
| 1449 | + break; | |
| 1450 | + default: | |
| 1451 | + x = get_reg(RC_FLOAT); | |
| 1452 | + ++vtop; | |
| 1453 | + vtop[0].r = x; | |
| 1454 | + x = fltr(x); | |
| 1455 | + break; | |
| 1456 | + } | |
| 1457 | + | |
| 1458 | + switch (op) { | |
| 1459 | + case '*': | |
| 1460 | + o(0x1e200800 | dbl << 22 | x | a << 5 | b << 16); // fmul | |
| 1461 | + break; | |
| 1462 | + case '+': | |
| 1463 | + o(0x1e202800 | dbl << 22 | x | a << 5 | b << 16); // fadd | |
| 1464 | + break; | |
| 1465 | + case '-': | |
| 1466 | + o(0x1e203800 | dbl << 22 | x | a << 5 | b << 16); // fsub | |
| 1467 | + break; | |
| 1468 | + case '/': | |
| 1469 | + o(0x1e201800 | dbl << 22 | x | a << 5 | b << 16); // fdiv | |
| 1470 | + break; | |
| 1471 | + case TOK_EQ: | |
| 1472 | + o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp | |
| 1473 | + o(0x1a9f17e0 | x); // cset w(x),eq | |
| 1474 | + break; | |
| 1475 | + case TOK_GE: | |
| 1476 | + o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp | |
| 1477 | + o(0x1a9fb7e0 | x); // cset w(x),ge | |
| 1478 | + break; | |
| 1479 | + case TOK_GT: | |
| 1480 | + o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp | |
| 1481 | + o(0x1a9fd7e0 | x); // cset w(x),gt | |
| 1482 | + break; | |
| 1483 | + case TOK_LE: | |
| 1484 | + o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp | |
| 1485 | + o(0x1a9f87e0 | x); // cset w(x),ls | |
| 1486 | + break; | |
| 1487 | + case TOK_LT: | |
| 1488 | + o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp | |
| 1489 | + o(0x1a9f57e0 | x); // cset w(x),mi | |
| 1490 | + break; | |
| 1491 | + case TOK_NE: | |
| 1492 | + o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp | |
| 1493 | + o(0x1a9f07e0 | x); // cset w(x),ne | |
| 1494 | + break; | |
| 1495 | + default: | |
| 1496 | + assert(0); | |
| 1497 | + } | |
| 1498 | +} | |
| 1499 | + | |
| 1500 | +// Generate sign extension from 32 to 64 bits: | |
| 1501 | +ST_FUNC void gen_cvt_sxtw(void) | |
| 1502 | +{ | |
| 1503 | + int r = intr(gv(RC_INT)); | |
| 1504 | + o(0x93407c00 | r | r << 5); // sxtw x(r),w(r) | |
| 1505 | +} | |
| 1506 | + | |
| 1507 | +ST_FUNC void gen_cvt_itof(int t) | |
| 1508 | +{ | |
| 1509 | + if (t == VT_LDOUBLE) { | |
| 1510 | + int f = vtop->type.t; | |
| 1511 | + int func = (f & VT_BTYPE) == VT_LLONG ? | |
| 1512 | + (f & VT_UNSIGNED ? TOK___floatunditf : TOK___floatditf) : | |
| 1513 | + (f & VT_UNSIGNED ? TOK___floatunsitf : TOK___floatsitf); | |
| 1514 | + vpush_global_sym(&func_old_type, func); | |
| 1515 | + vrott(2); | |
| 1516 | + gfunc_call(1); | |
| 1517 | + vpushi(0); | |
| 1518 | + vtop->type.t = t; | |
| 1519 | + vtop->r = REG_FRET; | |
| 1520 | + return; | |
| 1521 | + } | |
| 1522 | + else { | |
| 1523 | + int d, n = intr(gv(RC_INT)); | |
| 1524 | + int s = !(vtop->type.t & VT_UNSIGNED); | |
| 1525 | + int l = ((vtop->type.t & VT_BTYPE) == VT_LLONG); | |
| 1526 | + --vtop; | |
| 1527 | + d = get_reg(RC_FLOAT); | |
| 1528 | + ++vtop; | |
| 1529 | + vtop[0].r = d; | |
| 1530 | + o(0x1e220000 | !s << 16 | (t != VT_FLOAT) << 22 | fltr(d) | | |
| 1531 | + l << 31 | n << 5); // [us]cvtf [sd](d),[wx](n) | |
| 1532 | + } | |
| 1533 | +} | |
| 1534 | + | |
| 1535 | +ST_FUNC void gen_cvt_ftoi(int t) | |
| 1536 | +{ | |
| 1537 | + if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { | |
| 1538 | + int func = (t & VT_BTYPE) == VT_LLONG ? | |
| 1539 | + (t & VT_UNSIGNED ? TOK___fixunstfdi : TOK___fixtfdi) : | |
| 1540 | + (t & VT_UNSIGNED ? TOK___fixunstfsi : TOK___fixtfsi); | |
| 1541 | + vpush_global_sym(&func_old_type, func); | |
| 1542 | + vrott(2); | |
| 1543 | + gfunc_call(1); | |
| 1544 | + vpushi(0); | |
| 1545 | + vtop->type.t = t; | |
| 1546 | + vtop->r = REG_IRET; | |
| 1547 | + return; | |
| 1548 | + } | |
| 1549 | + else { | |
| 1550 | + int d, n = fltr(gv(RC_FLOAT)); | |
| 1551 | + int l = ((vtop->type.t & VT_BTYPE) != VT_FLOAT); | |
| 1552 | + --vtop; | |
| 1553 | + d = get_reg(RC_INT); | |
| 1554 | + ++vtop; | |
| 1555 | + vtop[0].r = d; | |
| 1556 | + o(0x1e380000 | | |
| 1557 | + !!(t & VT_UNSIGNED) << 16 | | |
| 1558 | + ((t & VT_BTYPE) == VT_LLONG) << 31 | intr(d) | | |
| 1559 | + l << 22 | n << 5); // fcvtz[su] [wx](d),[sd](n) | |
| 1560 | + } | |
| 1561 | +} | |
| 1562 | + | |
| 1563 | +ST_FUNC void gen_cvt_ftof(int t) | |
| 1564 | +{ | |
| 1565 | + int f = vtop[0].type.t; | |
| 1566 | + assert(t == VT_FLOAT || t == VT_DOUBLE || t == VT_LDOUBLE); | |
| 1567 | + assert(f == VT_FLOAT || f == VT_DOUBLE || f == VT_LDOUBLE); | |
| 1568 | + if (t == f) | |
| 1569 | + return; | |
| 1570 | + | |
| 1571 | + if (t == VT_LDOUBLE || f == VT_LDOUBLE) { | |
| 1572 | + int func = (t == VT_LDOUBLE) ? | |
| 1573 | + (f == VT_FLOAT ? TOK___extendsftf2 : TOK___extenddftf2) : | |
| 1574 | + (t == VT_FLOAT ? TOK___trunctfsf2 : TOK___trunctfdf2); | |
| 1575 | + vpush_global_sym(&func_old_type, func); | |
| 1576 | + vrott(2); | |
| 1577 | + gfunc_call(1); | |
| 1578 | + vpushi(0); | |
| 1579 | + vtop->type.t = t; | |
| 1580 | + vtop->r = REG_FRET; | |
| 1581 | + } | |
| 1582 | + else { | |
| 1583 | + int x, a; | |
| 1584 | + gv(RC_FLOAT); | |
| 1585 | + assert(vtop[0].r < VT_CONST); | |
| 1586 | + a = fltr(vtop[0].r); | |
| 1587 | + --vtop; | |
| 1588 | + x = get_reg(RC_FLOAT); | |
| 1589 | + ++vtop; | |
| 1590 | + vtop[0].r = x; | |
| 1591 | + x = fltr(x); | |
| 1592 | + | |
| 1593 | + if (f == VT_FLOAT) | |
| 1594 | + o(0x1e22c000 | x | a << 5); // fcvt d(x),s(a) | |
| 1595 | + else | |
| 1596 | + o(0x1e624000 | x | a << 5); // fcvt s(x),d(a) | |
| 1597 | + } | |
| 1598 | +} | |
| 1599 | + | |
| 1600 | +ST_FUNC void ggoto(void) | |
| 1601 | +{ | |
| 1602 | + arm64_gen_bl_or_b(1); | |
| 1603 | + --vtop; | |
| 1604 | +} | |
| 1605 | + | |
| 1606 | +ST_FUNC void gen_vla_sp_save(int addr) { | |
| 1607 | + tcc_error("variable length arrays unsupported for this target"); | |
| 1608 | +} | |
| 1609 | + | |
| 1610 | +ST_FUNC void gen_vla_sp_restore(int addr) { | |
| 1611 | + tcc_error("variable length arrays unsupported for this target"); | |
| 1612 | +} | |
| 1613 | + | |
| 1614 | +ST_FUNC void gen_vla_alloc(CType *type, int align) { | |
| 1615 | + tcc_error("variable length arrays unsupported for this target"); | |
| 1616 | +} | |
| 1617 | + | |
| 1618 | +/* end of A64 code generator */ | |
| 1619 | +/*************************************************************/ | |
| 1620 | +#endif | |
| 1621 | +/*************************************************************/ | |
| @@ -99,6 +99,9 @@ classify_cpu () · 98 unmodified lines | ||
| 99 | 99 | esac |
| 100 | 100 | cpu="armv4l" |
| 101 | 101 | ;; |
| 102 | + aarch64) | |
| 103 | + cpu="aarch64" | |
| 104 | + ;; | |
| 102 | 105 | alpha) |
| 103 | 106 | cpu="alpha" |
| 104 | 107 | ;; |
| @@ -435,6 +438,9 @@ elif test "$cpu" = "armv4l" ; then · 330 unmodified lines | ||
| 435 | 438 | echo "ARCH=arm" >> config.mak |
| 436 | 439 | echo "#define HOST_ARM 1" >> $TMPH |
| 437 | 440 | echo "#define TCC_ARM_VERSION $cpuver" >> $TMPH |
| 441 | +elif test "$cpu" = "aarch64" ; then | |
| 442 | + echo "ARCH=arm64" >> config.mak | |
| 443 | + echo "#define HOST_ARM64 1" >> $TMPH | |
| 438 | 444 | elif test "$cpu" = "powerpc" ; then |
| 439 | 445 | echo "ARCH=ppc" >> config.mak |
| 440 | 446 | echo "#define HOST_PPC 1" >> $TMPH |
| @@ -7,6 +7,8 @@ · 6 unmodified lines | ||
| 7 | 7 | # define TRIPLET_ARCH "x86_64" |
| 8 | 8 | #elif defined(__arm__) |
| 9 | 9 | # define TRIPLET_ARCH "arm" |
| 10 | +#elif defined(__aarch64__) | |
| 11 | +# define TRIPLET_ARCH "aarch64" | |
| 10 | 12 | #else |
| 11 | 13 | # define TRIPLET_ARCH "unknown" |
| 12 | 14 | #endif |
| @@ -2336,6 +2336,117 @@ typedef Elf32_Addr Elf32_Conflict; · 2335 unmodified lines | ||
| 2336 | 2336 | #define R_AARCH64_NONE 0 /* No relocation. */ |
| 2337 | 2337 | #define R_AARCH64_ABS64 257 /* Direct 64 bit. */ |
| 2338 | 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 | 2450 | #define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */ |
| 2340 | 2451 | #define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */ |
| 2341 | 2452 | #define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */ |
| @@ -2344,6 +2455,7 @@ typedef Elf32_Addr Elf32_Conflict; · 2 unmodified lines | ||
| 2344 | 2455 | #define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */ |
| 2345 | 2456 | #define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */ |
| 2346 | 2457 | #define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */ |
| 2458 | +#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */ | |
| 2347 | 2459 | |
| 2348 | 2460 | /* ARM relocs. */ |
| 2349 | 2461 | |
| @@ -46,6 +46,19 @@ typedef char *va_list; · 45 unmodified lines | ||
| 46 | 46 | #define va_copy(dest, src) (dest) = (src) |
| 47 | 47 | #define va_end(ap) |
| 48 | 48 | |
| 49 | +#elif defined(__aarch64__) | |
| 50 | +typedef struct { | |
| 51 | + void *__stack; | |
| 52 | + void *__gr_top; | |
| 53 | + void *__vr_top; | |
| 54 | + int __gr_offs; | |
| 55 | + int __vr_offs; | |
| 56 | +} va_list; | |
| 57 | +#define va_start(ap, last) __va_start(ap, last) | |
| 58 | +#define va_arg(ap, type) __va_arg(ap, type) | |
| 59 | +#define va_end(ap) | |
| 60 | +#define va_copy(dest, src) ((dest) = (src)) | |
| 61 | + | |
| 49 | 62 | #else /* __i386__ */ |
| 50 | 63 | typedef char *va_list; |
| 51 | 64 | /* only correct for i386 */ |
| @@ -28,6 +28,11 @@ ifndef TARGET # native library · 27 unmodified lines | ||
| 28 | 28 | ifeq ($(ARCH),arm) |
| 29 | 29 | TARGET = arm |
| 30 | 30 | XCC = $(CC) |
| 31 | + else | |
| 32 | + ifeq ($(ARCH),arm64) | |
| 33 | + TARGET = arm64 | |
| 34 | + else | |
| 35 | + endif | |
| 31 | 36 | endif |
| 32 | 37 | endif |
| 33 | 38 | endif |
| @@ -49,6 +54,7 @@ X86_64_O = libtcc1.o alloca86_64.o · 15 unmodified lines | ||
| 49 | 54 | ARM_O = libtcc1.o armeabi.o alloca-arm.o |
| 50 | 55 | WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o |
| 51 | 56 | WIN64_O = $(X86_64_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o |
| 57 | +ARM64_O = lib-arm64.o | |
| 52 | 58 | |
| 53 | 59 | # build TCC runtime library to contain PIC code, so it can be linked |
| 54 | 60 | # into shared libraries |
| @@ -86,6 +92,11 @@ ifeq "$(TARGET)" "arm" · 31 unmodified lines | ||
| 86 | 92 | OBJ = $(addprefix $(DIR)/,$(ARM_O)) |
| 87 | 93 | TGT = -DTCC_TARGET_ARM |
| 88 | 94 | XCC ?= $(TCC) -B$(TOP) |
| 95 | +else | |
| 96 | +ifeq "$(TARGET)" "arm64" | |
| 97 | + OBJ = $(addprefix $(DIR)/,$(ARM64_O)) | |
| 98 | + TGT = -DTCC_TARGET_ARM64 | |
| 99 | + XCC ?= $(TCC) -B$(TOP) | |
| 89 | 100 | else |
| 90 | 101 | $(error libtcc1.a not supported on target '$(TARGET)') |
| 91 | 102 | endif |
| @@ -93,6 +104,7 @@ endif · 1 unmodified line | ||
| 93 | 104 | endif |
| 94 | 105 | endif |
| 95 | 106 | endif |
| 107 | +endif | |
| 96 | 108 | |
| 97 | 109 | XFLAGS = $(CPPFLAGS) $(CFLAGS) $(PICFLAGS) $(TGT) |
| 98 | 110 | |
| @@ -0,0 +1,652 @@ | ||
| 1 | +/* | |
| 2 | + * TCC runtime library for arm64. | |
| 3 | + * | |
| 4 | + * Copyright (c) 2015 Edmund Grimley Evans | |
| 5 | + * | |
| 6 | + * Copying and distribution of this file, with or without modification, | |
| 7 | + * are permitted in any medium without royalty provided the copyright | |
| 8 | + * notice and this notice are preserved. This file is offered as-is, | |
| 9 | + * without any warranty. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#include <stdint.h> | |
| 13 | +#include <string.h> | |
| 14 | + | |
| 15 | +void __clear_cache(char *beg, char *end) | |
| 16 | +{ | |
| 17 | +#warning __clear_cache not yet implemented | |
| 18 | +} | |
| 19 | + | |
| 20 | +typedef struct { | |
| 21 | + uint64_t x0, x1; | |
| 22 | +} u128_t; | |
| 23 | + | |
| 24 | +static long double f3_zero(int sgn) | |
| 25 | +{ | |
| 26 | + long double f; | |
| 27 | + u128_t x = { 0, (uint64_t)sgn << 63 }; | |
| 28 | + memcpy(&f, &x, 16); | |
| 29 | + return f; | |
| 30 | +} | |
| 31 | + | |
| 32 | +static long double f3_infinity(int sgn) | |
| 33 | +{ | |
| 34 | + long double f; | |
| 35 | + u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 }; | |
| 36 | + memcpy(&f, &x, 16); | |
| 37 | + return f; | |
| 38 | +} | |
| 39 | + | |
| 40 | +static long double f3_NaN(void) | |
| 41 | +{ | |
| 42 | + long double f; | |
| 43 | +#if 0 | |
| 44 | + // ARM's default NaN usually has just the top fraction bit set: | |
| 45 | + u128_t x = { 0, 0x7fff800000000000 }; | |
| 46 | +#else | |
| 47 | + // GCC's library sets all fraction bits: | |
| 48 | + u128_t x = { -1, 0x7fffffffffffffff }; | |
| 49 | +#endif | |
| 50 | + memcpy(&f, &x, 16); | |
| 51 | + return f; | |
| 52 | +} | |
| 53 | + | |
| 54 | +static int fp3_convert_NaN(long double *f, int sgn, u128_t mnt) | |
| 55 | +{ | |
| 56 | + u128_t x = { mnt.x0, | |
| 57 | + mnt.x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 }; | |
| 58 | + memcpy(f, &x, 16); | |
| 59 | + return 1; | |
| 60 | +} | |
| 61 | + | |
| 62 | +static int fp3_detect_NaNs(long double *f, | |
| 63 | + int a_sgn, int a_exp, u128_t a, | |
| 64 | + int b_sgn, int b_exp, u128_t b) | |
| 65 | +{ | |
| 66 | + // Detect signalling NaNs: | |
| 67 | + if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1)) | |
| 68 | + return fp3_convert_NaN(f, a_sgn, a); | |
| 69 | + if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1)) | |
| 70 | + return fp3_convert_NaN(f, b_sgn, b); | |
| 71 | + | |
| 72 | + // Detect quiet NaNs: | |
| 73 | + if (a_exp == 32767 && (a.x0 | a.x1 << 16)) | |
| 74 | + return fp3_convert_NaN(f, a_sgn, a); | |
| 75 | + if (b_exp == 32767 && (b.x0 | b.x1 << 16)) | |
| 76 | + return fp3_convert_NaN(f, b_sgn, b); | |
| 77 | + | |
| 78 | + return 0; | |
| 79 | +} | |
| 80 | + | |
| 81 | +static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f) | |
| 82 | +{ | |
| 83 | + u128_t x; | |
| 84 | + memcpy(&x, &f, 16); | |
| 85 | + *sgn = x.x1 >> 63; | |
| 86 | + *exp = x.x1 >> 48 & 32767; | |
| 87 | + x.x1 = x.x1 << 16 >> 16; | |
| 88 | + if (*exp) | |
| 89 | + x.x1 |= (uint64_t)1 << 48; | |
| 90 | + else | |
| 91 | + *exp = 1; | |
| 92 | + *mnt = x; | |
| 93 | +} | |
| 94 | + | |
| 95 | +static u128_t f3_normalise(int32_t *exp, u128_t mnt) | |
| 96 | +{ | |
| 97 | + int sh; | |
| 98 | + if (!(mnt.x0 | mnt.x1)) | |
| 99 | + return mnt; | |
| 100 | + if (!mnt.x1) { | |
| 101 | + mnt.x1 = mnt.x0; | |
| 102 | + mnt.x0 = 0; | |
| 103 | + *exp -= 64; | |
| 104 | + } | |
| 105 | + for (sh = 32; sh; sh >>= 1) { | |
| 106 | + if (!(mnt.x1 >> (64 - sh))) { | |
| 107 | + mnt.x1 = mnt.x1 << sh | mnt.x0 >> (64 - sh); | |
| 108 | + mnt.x0 = mnt.x0 << sh; | |
| 109 | + *exp -= sh; | |
| 110 | + } | |
| 111 | + } | |
| 112 | + return mnt; | |
| 113 | +} | |
| 114 | + | |
| 115 | +static u128_t f3_sticky_shift(int32_t sh, u128_t x) | |
| 116 | +{ | |
| 117 | + if (sh >= 128) { | |
| 118 | + x.x0 = !!(x.x0 | x.x1); | |
| 119 | + x.x1 = 0; | |
| 120 | + return x; | |
| 121 | + } | |
| 122 | + if (sh >= 64) { | |
| 123 | + x.x0 = x.x1 | !!x.x0; | |
| 124 | + x.x1 = 0; | |
| 125 | + sh -= 64; | |
| 126 | + } | |
| 127 | + if (sh > 0) { | |
| 128 | + x.x0 = x.x0 >> sh | x.x1 << (64 - sh) | !!(x.x0 << (64 - sh)); | |
| 129 | + x.x1 = x.x1 >> sh; | |
| 130 | + } | |
| 131 | + return x; | |
| 132 | +} | |
| 133 | + | |
| 134 | +static long double f3_round(int sgn, int32_t exp, u128_t x) | |
| 135 | +{ | |
| 136 | + long double f; | |
| 137 | + int error; | |
| 138 | + | |
| 139 | + if (exp > 0) { | |
| 140 | + x = f3_sticky_shift(13, x); | |
| 141 | + } | |
| 142 | + else { | |
| 143 | + x = f3_sticky_shift(14 - exp, x); | |
| 144 | + exp = 0; | |
| 145 | + } | |
| 146 | + | |
| 147 | + error = x.x0 & 3; | |
| 148 | + x.x0 = x.x0 >> 2 | x.x1 << 62; | |
| 149 | + x.x1 = x.x1 >> 2; | |
| 150 | + | |
| 151 | + if (error == 3 || ((error == 2) & (x.x0 & 1))) { | |
| 152 | + if (!++x.x0) { | |
| 153 | + ++x.x1; | |
| 154 | + if (x.x1 == (uint64_t)1 << 48) | |
| 155 | + exp = 1; | |
| 156 | + else if (x.x1 == (uint64_t)1 << 49) { | |
| 157 | + ++exp; | |
| 158 | + x.x0 = x.x0 >> 1 | x.x1 << 63; | |
| 159 | + x.x1 = x.x1 >> 1; | |
| 160 | + } | |
| 161 | + } | |
| 162 | + } | |
| 163 | + | |
| 164 | + if (exp >= 32767) | |
| 165 | + return f3_infinity(sgn); | |
| 166 | + | |
| 167 | + x.x1 = x.x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63; | |
| 168 | + memcpy(&f, &x, 16); | |
| 169 | + return f; | |
| 170 | +} | |
| 171 | + | |
| 172 | +static long double f3_add(long double fa, long double fb, int neg) | |
| 173 | +{ | |
| 174 | + u128_t a, b, x; | |
| 175 | + int32_t a_exp, b_exp, x_exp; | |
| 176 | + int a_sgn, b_sgn, x_sgn; | |
| 177 | + long double fx; | |
| 178 | + | |
| 179 | + f3_unpack(&a_sgn, &a_exp, &a, fa); | |
| 180 | + f3_unpack(&b_sgn, &b_exp, &b, fb); | |
| 181 | + | |
| 182 | + if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b)) | |
| 183 | + return fx; | |
| 184 | + | |
| 185 | + b_sgn ^= neg; | |
| 186 | + | |
| 187 | + // Handle infinities and zeroes: | |
| 188 | + if (a_exp == 32767 && b_exp == 32767 && a_sgn != b_sgn) | |
| 189 | + return f3_NaN(); | |
| 190 | + if (a_exp == 32767) | |
| 191 | + return f3_infinity(a_sgn); | |
| 192 | + if (b_exp == 32767) | |
| 193 | + return f3_infinity(b_sgn); | |
| 194 | + if (!(a.x0 | a.x1 | b.x0 | b.x1)) | |
| 195 | + return f3_zero(a_sgn & b_sgn); | |
| 196 | + | |
| 197 | + a.x1 = a.x1 << 3 | a.x0 >> 61; | |
| 198 | + a.x0 = a.x0 << 3; | |
| 199 | + b.x1 = b.x1 << 3 | b.x0 >> 61; | |
| 200 | + b.x0 = b.x0 << 3; | |
| 201 | + | |
| 202 | + if (a_exp <= b_exp) { | |
| 203 | + a = f3_sticky_shift(b_exp - a_exp, a); | |
| 204 | + a_exp = b_exp; | |
| 205 | + } | |
| 206 | + else { | |
| 207 | + b = f3_sticky_shift(a_exp - b_exp, b); | |
| 208 | + b_exp = a_exp; | |
| 209 | + } | |
| 210 | + | |
| 211 | + x_sgn = a_sgn; | |
| 212 | + x_exp = a_exp; | |
| 213 | + if (a_sgn == b_sgn) { | |
| 214 | + x.x0 = a.x0 + b.x0; | |
| 215 | + x.x1 = a.x1 + b.x1 + (x.x0 < a.x0); | |
| 216 | + } | |
| 217 | + else { | |
| 218 | + x.x0 = a.x0 - b.x0; | |
| 219 | + x.x1 = a.x1 - b.x1 - (x.x0 > a.x0); | |
| 220 | + if (x.x1 >> 63) { | |
| 221 | + x_sgn ^= 1; | |
| 222 | + x.x0 = -x.x0; | |
| 223 | + x.x1 = -x.x1 - !!x.x0; | |
| 224 | + } | |
| 225 | + } | |
| 226 | + | |
| 227 | + if (!(x.x0 | x.x1)) | |
| 228 | + return f3_zero(0); | |
| 229 | + | |
| 230 | + x = f3_normalise(&x_exp, x); | |
| 231 | + | |
| 232 | + return f3_round(x_sgn, x_exp + 12, x); | |
| 233 | +} | |
| 234 | + | |
| 235 | +long double __addtf3(long double a, long double b) | |
| 236 | +{ | |
| 237 | + return f3_add(a, b, 0); | |
| 238 | +} | |
| 239 | + | |
| 240 | +long double __subtf3(long double a, long double b) | |
| 241 | +{ | |
| 242 | + return f3_add(a, b, 1); | |
| 243 | +} | |
| 244 | + | |
| 245 | +long double __multf3(long double fa, long double fb) | |
| 246 | +{ | |
| 247 | + u128_t a, b, x; | |
| 248 | + int32_t a_exp, b_exp, x_exp; | |
| 249 | + int a_sgn, b_sgn, x_sgn; | |
| 250 | + long double fx; | |
| 251 | + | |
| 252 | + f3_unpack(&a_sgn, &a_exp, &a, fa); | |
| 253 | + f3_unpack(&b_sgn, &b_exp, &b, fb); | |
| 254 | + | |
| 255 | + if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b)) | |
| 256 | + return fx; | |
| 257 | + | |
| 258 | + // Handle infinities and zeroes: | |
| 259 | + if ((a_exp == 32767 && !(b.x0 | b.x1)) || | |
| 260 | + (b_exp == 32767 && !(a.x0 | a.x1))) | |
| 261 | + return f3_NaN(); | |
| 262 | + if (a_exp == 32767 || b_exp == 32767) | |
| 263 | + return f3_infinity(a_sgn ^ b_sgn); | |
| 264 | + if (!(a.x0 | a.x1) || !(b.x0 | b.x1)) | |
| 265 | + return f3_zero(a_sgn ^ b_sgn); | |
| 266 | + | |
| 267 | + a = f3_normalise(&a_exp, a); | |
| 268 | + b = f3_normalise(&b_exp, b); | |
| 269 | + | |
| 270 | + x_sgn = a_sgn ^ b_sgn; | |
| 271 | + x_exp = a_exp + b_exp - 16352; | |
| 272 | + | |
| 273 | + { | |
| 274 | + // Convert to base (1 << 30), discarding bottom 6 bits, which are zero, | |
| 275 | + // so there are (32, 30, 30, 30) bits in (a3, a2, a1, a0): | |
| 276 | + uint64_t a0 = a.x0 << 28 >> 34; | |
| 277 | + uint64_t b0 = b.x0 << 28 >> 34; | |
| 278 | + uint64_t a1 = a.x0 >> 36 | a.x1 << 62 >> 34; | |
| 279 | + uint64_t b1 = b.x0 >> 36 | b.x1 << 62 >> 34; | |
| 280 | + uint64_t a2 = a.x1 << 32 >> 34; | |
| 281 | + uint64_t b2 = b.x1 << 32 >> 34; | |
| 282 | + uint64_t a3 = a.x1 >> 32; | |
| 283 | + uint64_t b3 = b.x1 >> 32; | |
| 284 | + // Use 16 small multiplications and additions that do not overflow: | |
| 285 | + uint64_t x0 = a0 * b0; | |
| 286 | + uint64_t x1 = (x0 >> 30) + a0 * b1 + a1 * b0; | |
| 287 | + uint64_t x2 = (x1 >> 30) + a0 * b2 + a1 * b1 + a2 * b0; | |
| 288 | + uint64_t x3 = (x2 >> 30) + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; | |
| 289 | + uint64_t x4 = (x3 >> 30) + a1 * b3 + a2 * b2 + a3 * b1; | |
| 290 | + uint64_t x5 = (x4 >> 30) + a2 * b3 + a3 * b2; | |
| 291 | + uint64_t x6 = (x5 >> 30) + a3 * b3; | |
| 292 | + // We now have (64, 30, 30, ...) bits in (x6, x5, x4, ...). | |
| 293 | + // Take the top 128 bits, setting bottom bit if any lower bits were set: | |
| 294 | + uint64_t y0 = (x5 << 34 | x4 << 34 >> 30 | x3 << 34 >> 60 | | |
| 295 | + !!(x3 << 38 | (x2 | x1 | x0) << 34)); | |
| 296 | + uint64_t y1 = x6; | |
| 297 | + // Top bit may be zero. Renormalise: | |
| 298 | + if (!(y1 >> 63)) { | |
| 299 | + y1 = y1 << 1 | y0 >> 63; | |
| 300 | + y0 = y0 << 1; | |
| 301 | + --x_exp; | |
| 302 | + } | |
| 303 | + x.x0 = y0; | |
| 304 | + x.x1 = y1; | |
| 305 | + } | |
| 306 | + | |
| 307 | + return f3_round(x_sgn, x_exp, x); | |
| 308 | +} | |
| 309 | + | |
| 310 | +long double __divtf3(long double fa, long double fb) | |
| 311 | +{ | |
| 312 | + u128_t a, b, x; | |
| 313 | + int32_t a_exp, b_exp, x_exp; | |
| 314 | + int a_sgn, b_sgn, x_sgn, i; | |
| 315 | + long double fx; | |
| 316 | + | |
| 317 | + f3_unpack(&a_sgn, &a_exp, &a, fa); | |
| 318 | + f3_unpack(&b_sgn, &b_exp, &b, fb); | |
| 319 | + | |
| 320 | + if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b)) | |
| 321 | + return fx; | |
| 322 | + | |
| 323 | + // Handle infinities and zeroes: | |
| 324 | + if ((a_exp == 32767 && b_exp == 32767) || | |
| 325 | + (!(a.x0 | a.x1) && !(b.x0 | b.x1))) | |
| 326 | + return f3_NaN(); | |
| 327 | + if (a_exp == 32767 || !(b.x0 | b.x1)) | |
| 328 | + return f3_infinity(a_sgn ^ b_sgn); | |
| 329 | + if (!(a.x0 | a.x1) || b_exp == 32767) | |
| 330 | + return f3_zero(a_sgn ^ b_sgn); | |
| 331 | + | |
| 332 | + a = f3_normalise(&a_exp, a); | |
| 333 | + b = f3_normalise(&b_exp, b); | |
| 334 | + | |
| 335 | + x_sgn = a_sgn ^ b_sgn; | |
| 336 | + x_exp = a_exp - b_exp + 16395; | |
| 337 | + | |
| 338 | + a.x0 = a.x0 >> 1 | a.x1 << 63; | |
| 339 | + a.x1 = a.x1 >> 1; | |
| 340 | + b.x0 = b.x0 >> 1 | b.x1 << 63; | |
| 341 | + b.x1 = b.x1 >> 1; | |
| 342 | + x.x0 = 0; | |
| 343 | + x.x1 = 0; | |
| 344 | + for (i = 0; i < 116; i++) { | |
| 345 | + x.x1 = x.x1 << 1 | x.x0 >> 63; | |
| 346 | + x.x0 = x.x0 << 1; | |
| 347 | + if (a.x1 > b.x1 || (a.x1 == b.x1 && a.x0 >= b.x0)) { | |
| 348 | + a.x1 = a.x1 - b.x1 - (a.x0 < b.x0); | |
| 349 | + a.x0 = a.x0 - b.x0; | |
| 350 | + x.x0 |= 1; | |
| 351 | + } | |
| 352 | + a.x1 = a.x1 << 1 | a.x0 >> 63; | |
| 353 | + a.x0 = a.x0 << 1; | |
| 354 | + } | |
| 355 | + x.x0 |= !!(a.x0 | a.x1); | |
| 356 | + | |
| 357 | + x = f3_normalise(&x_exp, x); | |
| 358 | + | |
| 359 | + return f3_round(x_sgn, x_exp, x); | |
| 360 | +} | |
| 361 | + | |
| 362 | +long double __extendsftf2(float f) | |
| 363 | +{ | |
| 364 | + long double fx; | |
| 365 | + u128_t x; | |
| 366 | + uint32_t a; | |
| 367 | + uint64_t aa; | |
| 368 | + memcpy(&a, &f, 4); | |
| 369 | + aa = a; | |
| 370 | + x.x0 = 0; | |
| 371 | + if (!(a << 1)) | |
| 372 | + x.x1 = aa << 32; | |
| 373 | + else if (a << 1 >> 24 == 255) | |
| 374 | + x.x1 = (0x7fff000000000000 | aa >> 31 << 63 | aa << 41 >> 16 | | |
| 375 | + (uint64_t)!!(a << 9) << 47); | |
| 376 | + else | |
| 377 | + x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 | | |
| 378 | + aa << 41 >> 16); | |
| 379 | + memcpy(&fx, &x, 16); | |
| 380 | + return fx; | |
| 381 | +} | |
| 382 | + | |
| 383 | +long double __extenddftf2(double f) | |
| 384 | +{ | |
| 385 | + long double fx; | |
| 386 | + u128_t x; | |
| 387 | + uint64_t a; | |
| 388 | + memcpy(&a, &f, 8); | |
| 389 | + x.x0 = a << 60; | |
| 390 | + if (!(a << 1)) | |
| 391 | + x.x1 = a; | |
| 392 | + else if (a << 1 >> 53 == 2047) | |
| 393 | + x.x1 = (0x7fff000000000000 | a >> 63 << 63 | a << 12 >> 16 | | |
| 394 | + (uint64_t)!!(a << 12) << 47); | |
| 395 | + else | |
| 396 | + x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16; | |
| 397 | + memcpy(&fx, &x, 16); | |
| 398 | + return fx; | |
| 399 | +} | |
| 400 | + | |
| 401 | +float __trunctfsf2(long double f) | |
| 402 | +{ | |
| 403 | + u128_t mnt; | |
| 404 | + int32_t exp; | |
| 405 | + int sgn; | |
| 406 | + uint32_t x; | |
| 407 | + float fx; | |
| 408 | + | |
| 409 | + f3_unpack(&sgn, &exp, &mnt, f); | |
| 410 | + | |
| 411 | + if (exp == 32767 && (mnt.x0 | mnt.x1 << 16)) | |
| 412 | + x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff); | |
| 413 | + else if (exp > 16510) | |
| 414 | + x = 0x7f800000 | (uint32_t)sgn << 31; | |
| 415 | + else if (exp < 16233) | |
| 416 | + x = (uint32_t)sgn << 31; | |
| 417 | + else { | |
| 418 | + exp -= 16257; | |
| 419 | + x = mnt.x1 >> 23 | !!(mnt.x0 | mnt.x1 << 41); | |
| 420 | + if (exp < 0) { | |
| 421 | + x = x >> -exp | !!(x << (32 + exp)); | |
| 422 | + exp = 0; | |
| 423 | + } | |
| 424 | + if ((x & 3) == 3 || (x & 7) == 6) | |
| 425 | + x += 4; | |
| 426 | + x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31; | |
| 427 | + } | |
| 428 | + memcpy(&fx, &x, 4); | |
| 429 | + return fx; | |
| 430 | +} | |
| 431 | + | |
| 432 | +double __trunctfdf2(long double f) | |
| 433 | +{ | |
| 434 | + u128_t mnt; | |
| 435 | + int32_t exp; | |
| 436 | + int sgn; | |
| 437 | + uint64_t x; | |
| 438 | + double fx; | |
| 439 | + | |
| 440 | + f3_unpack(&sgn, &exp, &mnt, f); | |
| 441 | + | |
| 442 | + if (exp == 32767 && (mnt.x0 | mnt.x1 << 16)) | |
| 443 | + x = (0x7ff8000000000000 | (uint64_t)sgn << 63 | | |
| 444 | + mnt.x1 << 16 >> 12 | mnt.x0 >> 60); | |
| 445 | + else if (exp > 17406) | |
| 446 | + x = 0x7ff0000000000000 | (uint64_t)sgn << 63; | |
| 447 | + else if (exp < 15308) | |
| 448 | + x = (uint64_t)sgn << 63; | |
| 449 | + else { | |
| 450 | + exp -= 15361; | |
| 451 | + x = mnt.x1 << 6 | mnt.x0 >> 58 | !!(mnt.x0 << 6); | |
| 452 | + if (exp < 0) { | |
| 453 | + x = x >> -exp | !!(x << (64 + exp)); | |
| 454 | + exp = 0; | |
| 455 | + } | |
| 456 | + if ((x & 3) == 3 || (x & 7) == 6) | |
| 457 | + x += 4; | |
| 458 | + x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63; | |
| 459 | + } | |
| 460 | + memcpy(&fx, &x, 8); | |
| 461 | + return fx; | |
| 462 | +} | |
| 463 | + | |
| 464 | +int32_t __fixtfsi(long double fa) | |
| 465 | +{ | |
| 466 | + u128_t a; | |
| 467 | + int32_t a_exp; | |
| 468 | + int a_sgn; | |
| 469 | + int32_t x; | |
| 470 | + f3_unpack(&a_sgn, &a_exp, &a, fa); | |
| 471 | + if (a_exp < 16369) | |
| 472 | + return 0; | |
| 473 | + if (a_exp > 16413) | |
| 474 | + return a_sgn ? -0x80000000 : 0x7fffffff; | |
| 475 | + x = a.x1 >> (16431 - a_exp); | |
| 476 | + return a_sgn ? -x : x; | |
| 477 | +} | |
| 478 | + | |
| 479 | +int64_t __fixtfdi(long double fa) | |
| 480 | +{ | |
| 481 | + u128_t a; | |
| 482 | + int32_t a_exp; | |
| 483 | + int a_sgn; | |
| 484 | + int64_t x; | |
| 485 | + f3_unpack(&a_sgn, &a_exp, &a, fa); | |
| 486 | + if (a_exp < 16383) | |
| 487 | + return 0; | |
| 488 | + if (a_exp > 16445) | |
| 489 | + return a_sgn ? -0x8000000000000000 : 0x7fffffffffffffff; | |
| 490 | + x = (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp); | |
| 491 | + return a_sgn ? -x : x; | |
| 492 | +} | |
| 493 | + | |
| 494 | +uint32_t __fixunstfsi(long double fa) | |
| 495 | +{ | |
| 496 | + u128_t a; | |
| 497 | + int32_t a_exp; | |
| 498 | + int a_sgn; | |
| 499 | + f3_unpack(&a_sgn, &a_exp, &a, fa); | |
| 500 | + if (a_sgn || a_exp < 16369) | |
| 501 | + return 0; | |
| 502 | + if (a_exp > 16414) | |
| 503 | + return -1; | |
| 504 | + return a.x1 >> (16431 - a_exp); | |
| 505 | +} | |
| 506 | + | |
| 507 | +uint64_t __fixunstfdi(long double fa) | |
| 508 | +{ | |
| 509 | + u128_t a; | |
| 510 | + int32_t a_exp; | |
| 511 | + int a_sgn; | |
| 512 | + f3_unpack(&a_sgn, &a_exp, &a, fa); | |
| 513 | + if (a_sgn || a_exp < 16383) | |
| 514 | + return 0; | |
| 515 | + if (a_exp > 16446) | |
| 516 | + return -1; | |
| 517 | + return (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp); | |
| 518 | +} | |
| 519 | + | |
| 520 | +long double __floatsitf(int32_t a) | |
| 521 | +{ | |
| 522 | + int sgn = 0; | |
| 523 | + int exp = 16414; | |
| 524 | + uint32_t mnt = a; | |
| 525 | + u128_t x = { 0, 0 }; | |
| 526 | + long double f; | |
| 527 | + int i; | |
| 528 | + if (a) { | |
| 529 | + if (a < 0) { | |
| 530 | + sgn = 1; | |
| 531 | + mnt = -mnt; | |
| 532 | + } | |
| 533 | + for (i = 16; i; i >>= 1) | |
| 534 | + if (!(mnt >> (32 - i))) { | |
| 535 | + mnt <<= i; | |
| 536 | + exp -= i; | |
| 537 | + } | |
| 538 | + x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 | | |
| 539 | + (uint64_t)(mnt << 1) << 16); | |
| 540 | + } | |
| 541 | + memcpy(&f, &x, 16); | |
| 542 | + return f; | |
| 543 | +} | |
| 544 | + | |
| 545 | +long double __floatditf(int64_t a) | |
| 546 | +{ | |
| 547 | + int sgn = 0; | |
| 548 | + int exp = 16446; | |
| 549 | + uint64_t mnt = a; | |
| 550 | + u128_t x = { 0, 0 }; | |
| 551 | + long double f; | |
| 552 | + int i; | |
| 553 | + if (a) { | |
| 554 | + if (a < 0) { | |
| 555 | + sgn = 1; | |
| 556 | + mnt = -mnt; | |
| 557 | + } | |
| 558 | + for (i = 32; i; i >>= 1) | |
| 559 | + if (!(mnt >> (64 - i))) { | |
| 560 | + mnt <<= i; | |
| 561 | + exp -= i; | |
| 562 | + } | |
| 563 | + x.x0 = mnt << 49; | |
| 564 | + x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16; | |
| 565 | + } | |
| 566 | + memcpy(&f, &x, 16); | |
| 567 | + return f; | |
| 568 | +} | |
| 569 | + | |
| 570 | +long double __floatunsitf(uint32_t a) | |
| 571 | +{ | |
| 572 | + int exp = 16414; | |
| 573 | + uint32_t mnt = a; | |
| 574 | + u128_t x = { 0, 0 }; | |
| 575 | + long double f; | |
| 576 | + int i; | |
| 577 | + if (a) { | |
| 578 | + for (i = 16; i; i >>= 1) | |
| 579 | + if (!(mnt >> (32 - i))) { | |
| 580 | + mnt <<= i; | |
| 581 | + exp -= i; | |
| 582 | + } | |
| 583 | + x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16; | |
| 584 | + } | |
| 585 | + memcpy(&f, &x, 16); | |
| 586 | + return f; | |
| 587 | +} | |
| 588 | + | |
| 589 | +long double __floatunditf(uint64_t a) | |
| 590 | +{ | |
| 591 | + int exp = 16446; | |
| 592 | + uint64_t mnt = a; | |
| 593 | + u128_t x = { 0, 0 }; | |
| 594 | + long double f; | |
| 595 | + int i; | |
| 596 | + if (a) { | |
| 597 | + for (i = 32; i; i >>= 1) | |
| 598 | + if (!(mnt >> (64 - i))) { | |
| 599 | + mnt <<= i; | |
| 600 | + exp -= i; | |
| 601 | + } | |
| 602 | + x.x0 = mnt << 49; | |
| 603 | + x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16; | |
| 604 | + } | |
| 605 | + memcpy(&f, &x, 16); | |
| 606 | + return f; | |
| 607 | +} | |
| 608 | + | |
| 609 | +static int f3_cmp(long double fa, long double fb) | |
| 610 | +{ | |
| 611 | + u128_t a, b; | |
| 612 | + memcpy(&a, &fa, 16); | |
| 613 | + memcpy(&b, &fb, 16); | |
| 614 | + return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 : | |
| 615 | + ((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) || | |
| 616 | + (b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 : | |
| 617 | + a.x1 >> 63 != b.x1 >> 63 ? (int)(b.x1 >> 63) - (int)(a.x1 >> 63) : | |
| 618 | + a.x1 < b.x1 ? (int)(a.x1 >> 63 << 1) - 1 : | |
| 619 | + a.x1 > b.x1 ? 1 - (int)(a.x1 >> 63 << 1) : | |
| 620 | + a.x0 < b.x0 ? (int)(a.x1 >> 63 << 1) - 1 : | |
| 621 | + b.x0 < a.x0 ? 1 - (int)(a.x1 >> 63 << 1) : 0); | |
| 622 | +} | |
| 623 | + | |
| 624 | +int __eqtf2(long double a, long double b) | |
| 625 | +{ | |
| 626 | + return !!f3_cmp(a, b); | |
| 627 | +} | |
| 628 | + | |
| 629 | +int __netf2(long double a, long double b) | |
| 630 | +{ | |
| 631 | + return !!f3_cmp(a, b); | |
| 632 | +} | |
| 633 | + | |
| 634 | +int __lttf2(long double a, long double b) | |
| 635 | +{ | |
| 636 | + return f3_cmp(a, b); | |
| 637 | +} | |
| 638 | + | |
| 639 | +int __letf2(long double a, long double b) | |
| 640 | +{ | |
| 641 | + return f3_cmp(a, b); | |
| 642 | +} | |
| 643 | + | |
| 644 | +int __gttf2(long double a, long double b) | |
| 645 | +{ | |
| 646 | + return -f3_cmp(b, a); | |
| 647 | +} | |
| 648 | + | |
| 649 | +int __getf2(long double a, long double b) | |
| 650 | +{ | |
| 651 | + return -f3_cmp(b, a); | |
| 652 | +} | |
| @@ -0,0 +1,510 @@ | ||
| 1 | +/* | |
| 2 | + * Test 128-bit floating-point arithmetic on arm64: | |
| 3 | + * build with two different compilers and compare the output. | |
| 4 | + * | |
| 5 | + * Copyright (c) 2015 Edmund Grimley Evans | |
| 6 | + * | |
| 7 | + * Copying and distribution of this file, with or without modification, | |
| 8 | + * are permitted in any medium without royalty provided the copyright | |
| 9 | + * notice and this notice are preserved. This file is offered as-is, | |
| 10 | + * without any warranty. | |
| 11 | + */ | |
| 12 | + | |
| 13 | +#include <stdint.h> | |
| 14 | +#include <stdio.h> | |
| 15 | +#include <stdlib.h> | |
| 16 | +#include <string.h> | |
| 17 | + | |
| 18 | +#define check(x) ((x) ? (void)0 : check_fail(#x, __FILE__, __LINE__)) | |
| 19 | + | |
| 20 | +void check_fail(const char *assertion, const char *file, unsigned int line) | |
| 21 | +{ | |
| 22 | + printf("%s:%d: Check (%s) failed.", file, line, assertion); | |
| 23 | + exit(1); | |
| 24 | +} | |
| 25 | + | |
| 26 | +typedef struct { | |
| 27 | + unsigned long long x0, x1; | |
| 28 | +} u128_t; | |
| 29 | + | |
| 30 | +float copy_fi(uint32_t x) | |
| 31 | +{ | |
| 32 | + float f; | |
| 33 | + memcpy(&f, &x, 4); | |
| 34 | + return f; | |
| 35 | +} | |
| 36 | + | |
| 37 | +double copy_di(uint64_t x) | |
| 38 | +{ | |
| 39 | + double f; | |
| 40 | + memcpy(&f, &x, 8); | |
| 41 | + return f; | |
| 42 | +} | |
| 43 | + | |
| 44 | +long double copy_ldi(u128_t x) | |
| 45 | +{ | |
| 46 | + long double f; | |
| 47 | + memcpy(&f, &x, 16); | |
| 48 | + return f; | |
| 49 | +} | |
| 50 | + | |
| 51 | +uint32_t copy_if(float f) | |
| 52 | +{ | |
| 53 | + uint32_t x; | |
| 54 | + memcpy(&x, &f, 4); | |
| 55 | + return x; | |
| 56 | +} | |
| 57 | + | |
| 58 | +uint64_t copy_id(double f) | |
| 59 | +{ | |
| 60 | + uint64_t x; | |
| 61 | + memcpy(&x, &f, 8); | |
| 62 | + return x; | |
| 63 | +} | |
| 64 | + | |
| 65 | +u128_t copy_ild(long double f) | |
| 66 | +{ | |
| 67 | + u128_t x; | |
| 68 | + memcpy(&x, &f, 16); | |
| 69 | + return x; | |
| 70 | +} | |
| 71 | + | |
| 72 | +long double make(int sgn, int exp, uint64_t high, uint64_t low) | |
| 73 | +{ | |
| 74 | + u128_t x = { low, | |
| 75 | + (0x0000ffffffffffff & high) | | |
| 76 | + (0x7fff000000000000 & (uint64_t)exp << 48) | | |
| 77 | + (0x8000000000000000 & (uint64_t)sgn << 63) }; | |
| 78 | + return copy_ldi(x); | |
| 79 | +} | |
| 80 | + | |
| 81 | +void cmp(long double a, long double b) | |
| 82 | +{ | |
| 83 | + u128_t ax = copy_ild(a); | |
| 84 | + u128_t bx = copy_ild(b); | |
| 85 | + int eq = (a == b); | |
| 86 | + int ne = (a != b); | |
| 87 | + int lt = (a < b); | |
| 88 | + int le = (a <= b); | |
| 89 | + int gt = (a > b); | |
| 90 | + int ge = (a >= b); | |
| 91 | + | |
| 92 | + check(eq == 0 || eq == 1); | |
| 93 | + check(lt == 0 || lt == 1); | |
| 94 | + check(gt == 0 || gt == 1); | |
| 95 | + check(ne == !eq && le == (lt | eq) && ge == (gt | eq)); | |
| 96 | + check(eq + lt + gt < 2); | |
| 97 | + | |
| 98 | + printf("cmp %016llx%016llx %016llx%016llx %d %d %d\n", | |
| 99 | + ax.x1, ax.x0, bx.x1, bx.x0, lt, eq, gt); | |
| 100 | +} | |
| 101 | + | |
| 102 | +void cmps(void) | |
| 103 | +{ | |
| 104 | + int i, j; | |
| 105 | + | |
| 106 | + for (i = 0; i < 2; i++) | |
| 107 | + for (j = 0; j < 2; j++) | |
| 108 | + cmp(make(i, 0, 0, 0), make(j, 0, 0, 0)); | |
| 109 | + | |
| 110 | + for (i = 0; i < 2; i++) { | |
| 111 | + for (j = 0; j < 64; j++) { | |
| 112 | + long double f1 = make(i, 32767, (uint64_t)1 << j, 0); | |
| 113 | + long double f2 = make(i, 32767, 0, (uint64_t)1 << j); | |
| 114 | + cmp(f1, 0); | |
| 115 | + cmp(f2, 0); | |
| 116 | + cmp(0, f1); | |
| 117 | + cmp(0, f2); | |
| 118 | + } | |
| 119 | + } | |
| 120 | + | |
| 121 | + for (i = 0; i < 6; i++) | |
| 122 | + for (j = 0; j < 6; j++) | |
| 123 | + cmp(make(i & 1, i >> 1, 0, 0), | |
| 124 | + make(j & 1, j >> 1, 0, 0)); | |
| 125 | + | |
| 126 | + for (i = 0; i < 2; i++) { | |
| 127 | + for (j = 0; j < 2; j++) { | |
| 128 | + int a, b; | |
| 129 | + for (a = 0; a < 2; a++) { | |
| 130 | + for (b = 0; b < 2; b++) { | |
| 131 | + cmp(make(i, j, a, b), make(i, j, 0, 0)); | |
| 132 | + cmp(make(i, j, 0, 0), make(i, j, a, b)); | |
| 133 | + } | |
| 134 | + } | |
| 135 | + } | |
| 136 | + } | |
| 137 | +} | |
| 138 | + | |
| 139 | +void xop(const char *name, long double a, long double b, long double c) | |
| 140 | +{ | |
| 141 | + u128_t ax = copy_ild(a); | |
| 142 | + u128_t bx = copy_ild(b); | |
| 143 | + u128_t cx = copy_ild(c); | |
| 144 | + printf("%s %016llx%016llx %016llx%016llx %016llx%016llx\n", | |
| 145 | + name, ax.x1, ax.x0, bx.x1, bx.x0, cx.x1, cx.x0); | |
| 146 | +} | |
| 147 | + | |
| 148 | +void fadd(long double a, long double b) | |
| 149 | +{ | |
| 150 | + xop("add", a, b, a + b); | |
| 151 | +} | |
| 152 | + | |
| 153 | +void fsub(long double a, long double b) | |
| 154 | +{ | |
| 155 | + xop("sub", a, b, a - b); | |
| 156 | +} | |
| 157 | + | |
| 158 | +void fmul(long double a, long double b) | |
| 159 | +{ | |
| 160 | + xop("mul", a, b, a * b); | |
| 161 | +} | |
| 162 | + | |
| 163 | +void fdiv(long double a, long double b) | |
| 164 | +{ | |
| 165 | + xop("div", a, b, a / b); | |
| 166 | +} | |
| 167 | + | |
| 168 | +void nanz(void) | |
| 169 | +{ | |
| 170 | + // Check NaNs: | |
| 171 | + { | |
| 172 | + long double x[7]; | |
| 173 | + int i, j, n = 0; | |
| 174 | + x[n++] = make(0, 32000, 0x95132b76effc, 0xd79035214b4f8d53); | |
| 175 | + x[n++] = make(1, 32001, 0xbe71d7a51587, 0x30601c6815d6c3ac); | |
| 176 | + x[n++] = make(0, 32767, 0, 1); | |
| 177 | + x[n++] = make(0, 32767, (uint64_t)1 << 46, 0); | |
| 178 | + x[n++] = make(1, 32767, (uint64_t)1 << 47, 0); | |
| 179 | + x[n++] = make(1, 32767, 0x7596c7099ad5, 0xe25fed2c58f73fc9); | |
| 180 | + x[n++] = make(0, 32767, 0x835d143360f9, 0x5e315efb35630666); | |
| 181 | + check(n == sizeof(x) / sizeof(*x)); | |
| 182 | + for (i = 0; i < n; i++) { | |
| 183 | + for (j = 0; j < n; j++) { | |
| 184 | + fadd(x[i], x[j]); | |
| 185 | + fsub(x[i], x[j]); | |
| 186 | + fmul(x[i], x[j]); | |
| 187 | + fdiv(x[i], x[j]); | |
| 188 | + } | |
| 189 | + } | |
| 190 | + } | |
| 191 | + | |
| 192 | + // Check infinities and zeroes: | |
| 193 | + { | |
| 194 | + long double x[6]; | |
| 195 | + int i, j, n = 0; | |
| 196 | + x[n++] = make(1, 32000, 0x62acda85f700, 0x47b6c9f35edc4044); | |
| 197 | + x[n++] = make(0, 32001, 0x94b7abf55af7, 0x9f425fe354428e19); | |
| 198 | + x[n++] = make(0, 32767, 0, 0); | |
| 199 | + x[n++] = make(1, 32767, 0, 0); | |
| 200 | + x[n++] = make(0, 0, 0, 0); | |
| 201 | + x[n++] = make(1, 0, 0, 0); | |
| 202 | + check(n == sizeof(x) / sizeof(*x)); | |
| 203 | + for (i = 0; i < n; i++) { | |
| 204 | + for (j = 0; j < n; j++) { | |
| 205 | + fadd(x[i], x[j]); | |
| 206 | + fsub(x[i], x[j]); | |
| 207 | + fmul(x[i], x[j]); | |
| 208 | + fdiv(x[i], x[j]); | |
| 209 | + } | |
| 210 | + } | |
| 211 | + } | |
| 212 | +} | |
| 213 | + | |
| 214 | +void adds(void) | |
| 215 | +{ | |
| 216 | + // Check shifting and add/sub: | |
| 217 | + { | |
| 218 | + int i; | |
| 219 | + for (i = -130; i <= 130; i++) { | |
| 220 | + int s1 = (uint32_t)i % 3 < 1; | |
| 221 | + int s2 = (uint32_t)i % 5 < 2; | |
| 222 | + fadd(make(s1, 16384 , 0x502c065e4f71a65d, 0xd2f9bdb031f4f031), | |
| 223 | + make(s2, 16384 + i, 0xae267395a9bc1033, 0xb56b5800da1ba448)); | |
| 224 | + } | |
| 225 | + } | |
| 226 | + | |
| 227 | + // Check normalisation: | |
| 228 | + { | |
| 229 | + uint64_t a0 = 0xc6bab0a6afbef5ed; | |
| 230 | + uint64_t a1 = 0x4f84136c4a2e9b52; | |
| 231 | + int ee[] = { 0, 1, 10000 }; | |
| 232 | + int e, i; | |
| 233 | + for (e = 0; e < sizeof(ee) / sizeof(*ee); e++) { | |
| 234 | + int exp = ee[e]; | |
| 235 | + fsub(make(0, exp, a1, a0), make(0, 0, 0, 0)); | |
| 236 | + for (i = 63; i >= 0; i--) | |
| 237 | + fsub(make(0, exp, a1 | (uint64_t)1 << i >> 1, a0), | |
| 238 | + make(0, exp, a1 >> i << i, 0)); | |
| 239 | + for (i = 63; i >=0; i--) | |
| 240 | + fsub(make(0, exp, a1, a0 | (uint64_t)1 << i >> 1), | |
| 241 | + make(0, exp, a1, a0 >> i << i)); | |
| 242 | + } | |
| 243 | + } | |
| 244 | + | |
| 245 | + // Carry/overflow from rounding: | |
| 246 | + { | |
| 247 | + fadd(make(0, 114, -1, -1), make(0, 1, 0, 0)); | |
| 248 | + fadd(make(0, 32766, -1, -1), make(0, 32653, 0, 0)); | |
| 249 | + fsub(make(1, 32766, -1, -1), make(0, 32653, 0, 0)); | |
| 250 | + } | |
| 251 | +} | |
| 252 | + | |
| 253 | +void muls(void) | |
| 254 | +{ | |
| 255 | + int i, j; | |
| 256 | + | |
| 257 | + { | |
| 258 | + long double max = make(0, 32766, -1, -1); | |
| 259 | + long double min = make(0, 0, 0, 1); | |
| 260 | + fmul(max, max); | |
| 261 | + fmul(max, min); | |
| 262 | + fmul(min, min); | |
| 263 | + } | |
| 264 | + | |
| 265 | + for (i = 117; i > 0; i--) | |
| 266 | + fmul(make(0, 16268, 0x643dcea76edc, 0xe0877a598403627a), | |
| 267 | + make(i & 1, i, 0, 0)); | |
| 268 | + | |
| 269 | + fmul(make(0, 16383, -1, -3), make(0, 16383, 0, 1)); | |
| 270 | + // Round to next exponent: | |
| 271 | + fmul(make(0, 16383, -1, -2), make(0, 16383, 0, 1)); | |
| 272 | + // Round from subnormal to normal: | |
| 273 | + fmul(make(0, 1, -1, -1), make(0, 16382, 0, 0)); | |
| 274 | + | |
| 275 | + for (i = 0; i < 2; i++) | |
| 276 | + for (j = 0; j < 112; j++) | |
| 277 | + fmul(make(0, 16383, (uint64_t)1 << i, 0), | |
| 278 | + make(0, 16383, | |
| 279 | + j < 64 ? 0 : (uint64_t)1 << (j - 64), | |
| 280 | + j < 64 ? (uint64_t)1 << j : 0)); | |
| 281 | +} | |
| 282 | + | |
| 283 | +void divs(void) | |
| 284 | +{ | |
| 285 | + int i; | |
| 286 | + | |
| 287 | + { | |
| 288 | + long double max = make(0, 32766, -1, -1); | |
| 289 | + long double min = make(0, 0, 0, 1); | |
| 290 | + fdiv(max, max); | |
| 291 | + fdiv(max, min); | |
| 292 | + fdiv(min, max); | |
| 293 | + fdiv(min, min); | |
| 294 | + } | |
| 295 | + | |
| 296 | + for (i = 0; i < 64; i++) | |
| 297 | + fdiv(make(0, 16383, -1, -1), make(0, 16383, -1, -(uint64_t)1 << i)); | |
| 298 | + for (i = 0; i < 48; i++) | |
| 299 | + fdiv(make(0, 16383, -1, -1), make(0, 16383, -(uint64_t)1 << i, 0)); | |
| 300 | +} | |
| 301 | + | |
| 302 | +void cvtlsw(int32_t a) | |
| 303 | +{ | |
| 304 | + long double f = a; | |
| 305 | + u128_t x = copy_ild(f); | |
| 306 | + printf("cvtlsw %08lx %016llx%016llx\n", (long)(uint32_t)a, x.x1, x.x0); | |
| 307 | +} | |
| 308 | + | |
| 309 | +void cvtlsx(int64_t a) | |
| 310 | +{ | |
| 311 | + long double f = a; | |
| 312 | + u128_t x = copy_ild(f); | |
| 313 | + printf("cvtlsx %016llx %016llx%016llx\n", | |
| 314 | + (long long)(uint64_t)a, x.x1, x.x0); | |
| 315 | +} | |
| 316 | + | |
| 317 | +void cvtluw(uint32_t a) | |
| 318 | +{ | |
| 319 | + long double f = a; | |
| 320 | + u128_t x = copy_ild(f); | |
| 321 | + printf("cvtluw %08lx %016llx%016llx\n", (long)a, x.x1, x.x0); | |
| 322 | +} | |
| 323 | + | |
| 324 | +void cvtlux(uint64_t a) | |
| 325 | +{ | |
| 326 | + long double f = a; | |
| 327 | + u128_t x = copy_ild(f); | |
| 328 | + printf("cvtlux %016llx %016llx%016llx\n", (long long)a, x.x1, x.x0); | |
| 329 | +} | |
| 330 | + | |
| 331 | +void cvtil(long double a) | |
| 332 | +{ | |
| 333 | + u128_t x = copy_ild(a); | |
| 334 | + int32_t b1 = a; | |
| 335 | + int64_t b2 = a; | |
| 336 | + uint32_t b3 = a; | |
| 337 | + uint64_t b4 = a; | |
| 338 | + printf("cvtswl %016llx%016llx %08lx\n", | |
| 339 | + x.x1, x.x0, (long)(uint32_t)b1); | |
| 340 | + printf("cvtsxl %016llx%016llx %016llx\n", | |
| 341 | + x.x1, x.x0, (long long)(uint64_t)b2); | |
| 342 | + printf("cvtuwl %016llx%016llx %08lx\n", | |
| 343 | + x.x1, x.x0, (long)b3); | |
| 344 | + printf("cvtuxl %016llx%016llx %016llx\n", | |
| 345 | + x.x1, x.x0, (long long)b4); | |
| 346 | +} | |
| 347 | + | |
| 348 | +void cvtlf(float a) | |
| 349 | +{ | |
| 350 | + uint32_t ax = copy_if(a); | |
| 351 | + long double b = a; | |
| 352 | + u128_t bx = copy_ild(b); | |
| 353 | + printf("cvtlf %08lx %016llx%016llx\n", (long)ax, bx.x1, bx.x0); | |
| 354 | +} | |
| 355 | + | |
| 356 | +void cvtld(double a) | |
| 357 | +{ | |
| 358 | + uint64_t ax = copy_id(a); | |
| 359 | + long double b = a; | |
| 360 | + u128_t bx = copy_ild(b); | |
| 361 | + printf("cvtld %016llx %016llx%016llx\n", (long long)ax, bx.x1, bx.x0); | |
| 362 | +} | |
| 363 | + | |
| 364 | +void cvtfl(long double a) | |
| 365 | +{ | |
| 366 | + u128_t ax = copy_ild(a); | |
| 367 | + float b = a; | |
| 368 | + uint32_t bx = copy_if(b); | |
| 369 | + printf("cvtfl %016llx%016llx %08lx\n", ax.x1, ax.x0, (long)bx); | |
| 370 | +} | |
| 371 | + | |
| 372 | +void cvtdl(long double a) | |
| 373 | +{ | |
| 374 | + u128_t ax = copy_ild(a); | |
| 375 | + double b = a; | |
| 376 | + uint64_t bx = copy_id(b); | |
| 377 | + printf("cvtdl %016llx%016llx %016llx\n", ax.x1, ax.x0, (long long)bx); | |
| 378 | +} | |
| 379 | + | |
| 380 | +void cvts(void) | |
| 381 | +{ | |
| 382 | + int i, j; | |
| 383 | + | |
| 384 | + { | |
| 385 | + uint32_t x = 0xad040c5b; | |
| 386 | + cvtlsw(0); | |
| 387 | + for (i = 0; i < 31; i++) | |
| 388 | + cvtlsw(x >> (31 - i)); | |
| 389 | + for (i = 0; i < 31; i++) | |
| 390 | + cvtlsw(-(x >> (31 - i))); | |
| 391 | + cvtlsw(0x80000000); | |
| 392 | + } | |
| 393 | + { | |
| 394 | + uint64_t x = 0xb630a248cad9afd2; | |
| 395 | + cvtlsx(0); | |
| 396 | + for (i = 0; i < 63; i++) | |
| 397 | + cvtlsx(x >> (63 - i)); | |
| 398 | + for (i = 0; i < 63; i++) | |
| 399 | + cvtlsx(-(x >> (63 - i))); | |
| 400 | + cvtlsx(0x8000000000000000); | |
| 401 | + } | |
| 402 | + { | |
| 403 | + uint32_t x = 0xad040c5b; | |
| 404 | + cvtluw(0); | |
| 405 | + for (i = 0; i < 32; i++) | |
| 406 | + cvtluw(x >> (31 - i)); | |
| 407 | + } | |
| 408 | + { | |
| 409 | + uint64_t x = 0xb630a248cad9afd2; | |
| 410 | + cvtlux(0); | |
| 411 | + for (i = 0; i < 64; i++) | |
| 412 | + cvtlux(x >> (63 - i)); | |
| 413 | + } | |
| 414 | + | |
| 415 | + for (i = 0; i < 2; i++) { | |
| 416 | + cvtil(make(i, 32767, 0, 1)); | |
| 417 | + cvtil(make(i, 32767, (uint64_t)1 << 47, 0)); | |
| 418 | + cvtil(make(i, 32767, 123, 456)); | |
| 419 | + cvtil(make(i, 32767, 0, 0)); | |
| 420 | + cvtil(make(i, 16382, -1, -1)); | |
| 421 | + cvtil(make(i, 16383, -1, -1)); | |
| 422 | + cvtil(make(i, 16384, 0x7fffffffffff, -1)); | |
| 423 | + cvtil(make(i, 16384, 0x800000000000, 0)); | |
| 424 | + for (j = 0; j < 68; j++) | |
| 425 | + cvtil(make(i, 16381 + j, 0xd4822c0a10ec, 0x1fe2f8b2669f5c9d)); | |
| 426 | + } | |
| 427 | + | |
| 428 | + cvtlf(copy_fi(0x00000000)); | |
| 429 | + cvtlf(copy_fi(0x456789ab)); | |
| 430 | + cvtlf(copy_fi(0x7f800000)); | |
| 431 | + cvtlf(copy_fi(0x7f923456)); | |
| 432 | + cvtlf(copy_fi(0x7fdbcdef)); | |
| 433 | + cvtlf(copy_fi(0x80000000)); | |
| 434 | + cvtlf(copy_fi(0xabcdef12)); | |
| 435 | + cvtlf(copy_fi(0xff800000)); | |
| 436 | + cvtlf(copy_fi(0xff923456)); | |
| 437 | + cvtlf(copy_fi(0xffdbcdef)); | |
| 438 | + | |
| 439 | + cvtld(copy_di(0x0000000000000000)); | |
| 440 | + cvtld(copy_di(0x456789abcdef0123)); | |
| 441 | + cvtld(copy_di(0x7ff0000000000000)); | |
| 442 | + cvtld(copy_di(0x7ff123456789abcd)); | |
| 443 | + cvtld(copy_di(0x7ffabcdef1234567)); | |
| 444 | + cvtld(copy_di(0x8000000000000000)); | |
| 445 | + cvtld(copy_di(0xcdef123456789abc)); | |
| 446 | + cvtld(copy_di(0xfff0000000000000)); | |
| 447 | + cvtld(copy_di(0xfff123456789abcd)); | |
| 448 | + cvtld(copy_di(0xfffabcdef1234567)); | |
| 449 | + | |
| 450 | + for (i = 0; i < 2; i++) { \ | |
| 451 | + cvtfl(make(i, 0, 0, 0)); | |
| 452 | + cvtfl(make(i, 16232, -1, -1)); | |
| 453 | + cvtfl(make(i, 16233, 0, 0)); | |
| 454 | + cvtfl(make(i, 16233, 0, 1)); | |
| 455 | + cvtfl(make(i, 16383, 0xab0ffd000000, 0)); | |
| 456 | + cvtfl(make(i, 16383, 0xab0ffd000001, 0)); | |
| 457 | + cvtfl(make(i, 16383, 0xab0ffeffffff, 0)); | |
| 458 | + cvtfl(make(i, 16383, 0xab0fff000000, 0)); | |
| 459 | + cvtfl(make(i, 16383, 0xab0fff000001, 0)); | |
| 460 | + cvtfl(make(i, 16510, 0xfffffeffffff, -1)); | |
| 461 | + cvtfl(make(i, 16510, 0xffffff000000, 0)); | |
| 462 | + cvtfl(make(i, 16511, 0, 0)); | |
| 463 | + cvtfl(make(i, 32767, 0, 0)); | |
| 464 | + cvtfl(make(i, 32767, 0, 1)); | |
| 465 | + cvtfl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5)); | |
| 466 | + cvtfl(make(i, 32767, 0x800000000000, 1)); | |
| 467 | + cvtfl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099)); | |
| 468 | + } | |
| 469 | + | |
| 470 | + for (i = 0; i < 2; i++) { | |
| 471 | + cvtdl(make(i, 0, 0, 0)); | |
| 472 | + cvtdl(make(i, 15307, -1, -1)); | |
| 473 | + cvtdl(make(i, 15308, 0, 0)); | |
| 474 | + cvtdl(make(i, 15308, 0, 1)); | |
| 475 | + cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000000)); | |
| 476 | + cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000001)); | |
| 477 | + cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf7ffffffffffffff)); | |
| 478 | + cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000000)); | |
| 479 | + cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000001)); | |
| 480 | + cvtdl(make(i, 17406, 0xffffffffffff, 0xf7ffffffffffffff)); | |
| 481 | + cvtdl(make(i, 17406, 0xffffffffffff, 0xf800000000000000)); | |
| 482 | + cvtdl(make(i, 17407, 0, 0)); | |
| 483 | + cvtdl(make(i, 32767, 0, 0)); | |
| 484 | + cvtdl(make(i, 32767, 0, 1)); | |
| 485 | + cvtdl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5)); | |
| 486 | + cvtdl(make(i, 32767, 0x800000000000, 1)); | |
| 487 | + cvtdl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099)); | |
| 488 | + } | |
| 489 | +} | |
| 490 | + | |
| 491 | +void tests(void) | |
| 492 | +{ | |
| 493 | + cmps(); | |
| 494 | + nanz(); | |
| 495 | + adds(); | |
| 496 | + muls(); | |
| 497 | + divs(); | |
| 498 | + cvts(); | |
| 499 | +} | |
| 500 | + | |
| 501 | +int main() | |
| 502 | +{ | |
| 503 | +#ifdef __aarch64__ | |
| 504 | + tests(); | |
| 505 | +#else | |
| 506 | + printf("This test program is intended for a little-endian architecture\n" | |
| 507 | + "with an IEEE-standard 128-bit long double.\n"); | |
| 508 | +#endif | |
| 509 | + return 0; | |
| 510 | +} | |
| @@ -45,6 +45,9 @@ ST_DATA struct TCCState *tcc_state; · 44 unmodified lines | ||
| 45 | 45 | #ifdef TCC_TARGET_ARM |
| 46 | 46 | #include "arm-gen.c" |
| 47 | 47 | #endif |
| 48 | +#ifdef TCC_TARGET_ARM64 | |
| 49 | +#include "arm64-gen.c" | |
| 50 | +#endif | |
| 48 | 51 | #ifdef TCC_TARGET_C67 |
| 49 | 52 | #include "c67-gen.c" |
| 50 | 53 | #endif |
| @@ -959,6 +962,8 @@ LIBTCCAPI TCCState *tcc_new(void) · 908 unmodified lines | ||
| 959 | 962 | #else |
| 960 | 963 | s->float_abi = ARM_SOFTFP_FLOAT; |
| 961 | 964 | #endif |
| 965 | +#elif defined(TCC_TARGET_ARM64) | |
| 966 | + tcc_define_symbol(s, "__aarch64__", NULL); | |
| 962 | 967 | #endif |
| 963 | 968 | |
| 964 | 969 | #ifdef TCC_TARGET_PE |
| @@ -1560,7 +1565,7 @@ static int tcc_set_linker(TCCState *s, const char *option) · 595 unmodified lines | ||
| 1560 | 1565 | } else if (link_option(option, "oformat=", &p)) { |
| 1561 | 1566 | #if defined(TCC_TARGET_PE) |
| 1562 | 1567 | if (strstart("pe-", &p)) { |
| 1563 | −#elif defined(TCC_TARGET_X86_64) | |
| 1568 | +#elif defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 1564 | 1569 | if (strstart("elf64-", &p)) { |
| 1565 | 1570 | #else |
| 1566 | 1571 | if (strstart("elf32-", &p)) { |
| @@ -203,6 +203,8 @@ static void display_info(TCCState *s, int what) · 202 unmodified lines | ||
| 203 | 203 | # endif |
| 204 | 204 | #elif defined TCC_TARGET_ARM |
| 205 | 205 | "ARM" |
| 206 | +#elif defined TCC_TARGET_ARM64 | |
| 207 | + "AArch64" | |
| 206 | 208 | # ifdef TCC_ARM_HARDFLOAT |
| 207 | 209 | " Hard Float" |
| 208 | 210 | # endif |
| @@ -113,7 +113,7 @@ · 112 unmodified lines | ||
| 113 | 113 | #endif |
| 114 | 114 | |
| 115 | 115 | #include "elf.h" |
| 116 | −#ifdef TCC_TARGET_X86_64 | |
| 116 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 117 | 117 | # define ELFCLASSW ELFCLASS64 |
| 118 | 118 | # define ElfW(type) Elf##64##_##type |
| 119 | 119 | # define ELFW(type) ELF##64##_##type |
| @@ -151,23 +151,26 @@ · 31 unmodified lines | ||
| 151 | 151 | /* target selection */ |
| 152 | 152 | /* #define TCC_TARGET_I386 *//* i386 code generator */ |
| 153 | 153 | /* #define TCC_TARGET_ARM *//* ARMv4 code generator */ |
| 154 | +/* #define TCC_TARGET_ARM64 *//* ARMv8 code generator */ | |
| 154 | 155 | /* #define TCC_TARGET_C67 *//* TMS320C67xx code generator */ |
| 155 | 156 | /* #define TCC_TARGET_X86_64 *//* x86-64 code generator */ |
| 156 | 157 | |
| 157 | 158 | /* default target is I386 */ |
| 158 | 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 | 162 | #define TCC_TARGET_I386 |
| 161 | 163 | #endif |
| 162 | 164 | |
| 163 | 165 | #if !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \ |
| 164 | − !defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64) && \ | |
| 165 | − !defined(CONFIG_USE_LIBGCC) | |
| 166 | + !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \ | |
| 167 | + !defined(TCC_TARGET_X86_64) && !defined(CONFIG_USE_LIBGCC) | |
| 166 | 168 | #define CONFIG_TCC_BCHECK /* enable bound checking code */ |
| 167 | 169 | #endif |
| 168 | 170 | |
| 169 | 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 | 174 | #define CONFIG_TCC_ASM |
| 172 | 175 | #endif |
| 173 | 176 | |
| @@ -184,6 +187,8 @@ · 10 unmodified lines | ||
| 184 | 187 | # define TCC_IS_NATIVE |
| 185 | 188 | # elif defined __arm__ && defined TCC_TARGET_ARM |
| 186 | 189 | # define TCC_IS_NATIVE |
| 190 | +# elif defined __aarch64__ && defined TCC_TARGET_ARM64 | |
| 191 | +# define TCC_IS_NATIVE | |
| 187 | 192 | # endif |
| 188 | 193 | #endif |
| 189 | 194 | |
| @@ -256,6 +261,8 @@ · 66 unmodified lines | ||
| 256 | 261 | # define CONFIG_TCC_ELFINTERP "/usr/libexec/ld-elf.so.2" |
| 257 | 262 | # elif defined __GNU__ |
| 258 | 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 | 266 | # elif defined(TCC_TARGET_X86_64) |
| 260 | 267 | # define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2" |
| 261 | 268 | # elif defined(TCC_UCLIBC) |
| @@ -290,6 +297,9 @@ · 28 unmodified lines | ||
| 290 | 297 | #ifdef TCC_TARGET_ARM |
| 291 | 298 | # include "arm-gen.c" |
| 292 | 299 | #endif |
| 300 | +#ifdef TCC_TARGET_ARM64 | |
| 301 | +# include "arm64-gen.c" | |
| 302 | +#endif | |
| 293 | 303 | #ifdef TCC_TARGET_C67 |
| 294 | 304 | # include "coff.h" |
| 295 | 305 | # include "c67-gen.c" |
| @@ -1214,6 +1224,7 @@ ST_FUNC void vpushv(SValue *v); · 918 unmodified lines | ||
| 1214 | 1224 | ST_FUNC void save_reg(int r); |
| 1215 | 1225 | ST_FUNC int get_reg(int rc); |
| 1216 | 1226 | ST_FUNC void save_regs(int n); |
| 1227 | +ST_FUNC void gaddrof(void); | |
| 1217 | 1228 | ST_FUNC int gv(int rc); |
| 1218 | 1229 | ST_FUNC void gv2(int rc1, int rc2); |
| 1219 | 1230 | ST_FUNC void vpop(void); |
| @@ -1357,6 +1368,15 @@ ST_FUNC uint32_t encbranch(int pos, int addr, int fail); · 137 unmodified lines | ||
| 1357 | 1368 | ST_FUNC void gen_cvt_itof1(int t); |
| 1358 | 1369 | #endif |
| 1359 | 1370 | |
| 1371 | +/* ------------ arm64-gen.c ------------ */ | |
| 1372 | +#ifdef TCC_TARGET_ARM64 | |
| 1373 | +ST_FUNC void gen_cvt_sxtw(void); | |
| 1374 | +ST_FUNC void gen_opl(int op); | |
| 1375 | +ST_FUNC void greturn(void); | |
| 1376 | +ST_FUNC void gen_va_start(void); | |
| 1377 | +ST_FUNC void gen_va_arg(CType *t); | |
| 1378 | +#endif | |
| 1379 | + | |
| 1360 | 1380 | /* ------------ c67-gen.c ------------ */ |
| 1361 | 1381 | #ifdef TCC_TARGET_C67 |
| 1362 | 1382 | #endif |
| @@ -291,7 +291,7 @@ ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, · 290 unmodified lines | ||
| 291 | 291 | rel = section_ptr_add(sr, sizeof(ElfW_Rel)); |
| 292 | 292 | rel->r_offset = offset; |
| 293 | 293 | rel->r_info = ELFW(R_INFO)(symbol, type); |
| 294 | −#ifdef TCC_TARGET_X86_64 | |
| 294 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 295 | 295 | rel->r_addend = addend; |
| 296 | 296 | #else |
| 297 | 297 | if (addend) |
| @@ -506,7 +506,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 208 unmodified lines | ||
| 506 | 506 | sym_index = ELFW(R_SYM)(rel->r_info); |
| 507 | 507 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| 508 | 508 | val = sym->st_value; |
| 509 | −#ifdef TCC_TARGET_X86_64 | |
| 509 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 510 | 510 | val += rel->r_addend; |
| 511 | 511 | #endif |
| 512 | 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 | 760 | fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n", |
| 761 | 761 | type, (unsigned)addr, ptr, (unsigned)val); |
| 762 | 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 | 826 | #elif defined(TCC_TARGET_C67) |
| 764 | 827 | case R_C60_32: |
| 765 | 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 | 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) | |
| 959 | 1022 | static uint32_t get32(unsigned char *p) |
| 960 | 1023 | { |
| 961 | 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 | 1077 | (reloc_type == R_386_JMP_SLOT); |
| 1015 | 1078 | #elif defined(TCC_TARGET_ARM) |
| 1016 | 1079 | (reloc_type == R_ARM_JUMP_SLOT); |
| 1080 | +#elif defined(TCC_TARGET_ARM64) | |
| 1081 | + (reloc_type == R_AARCH64_JUMP_SLOT); | |
| 1017 | 1082 | #else |
| 1018 | 1083 | 0; |
| 1019 | 1084 | #endif |
| @@ -1135,6 +1200,24 @@ static unsigned long put_got_entry(TCCState *s1, · 115 unmodified lines | ||
| 1135 | 1200 | if (sym->st_shndx == SHN_UNDEF) |
| 1136 | 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 | 1221 | #elif defined(TCC_TARGET_C67) |
| 1139 | 1222 | if (s1->dynsym) { |
| 1140 | 1223 | tcc_error("C67 got not implemented"); |
| @@ -1277,6 +1360,18 @@ ST_FUNC void build_got_entries(TCCState *s1) · 136 unmodified lines | ||
| 1277 | 1360 | put32(p+2, 0x46c0); /* nop */ |
| 1278 | 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 | 1375 | #elif defined(TCC_TARGET_C67) |
| 1281 | 1376 | case R_C60_GOT32: |
| 1282 | 1377 | case R_C60_GOTOFF: |
| @@ -1796,6 +1891,40 @@ ST_FUNC void relocate_plt(TCCState *s1) · 513 unmodified lines | ||
| 1796 | 1891 | put32(p + 12, x + get32(p + 12) + s1->plt->data - p); |
| 1797 | 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 | 1928 | #elif defined(TCC_TARGET_C67) |
| 1800 | 1929 | /* XXX: TODO */ |
| 1801 | 1930 | #else |
| @@ -2093,7 +2222,7 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) · 291 unmodified lines | ||
| 2093 | 2222 | put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); |
| 2094 | 2223 | put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset); |
| 2095 | 2224 | put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym))); |
| 2096 | −#ifdef TCC_TARGET_X86_64 | |
| 2225 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 2097 | 2226 | put_dt(dynamic, DT_RELA, dyninf->rel_addr); |
| 2098 | 2227 | put_dt(dynamic, DT_RELASZ, dyninf->rel_size); |
| 2099 | 2228 | put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); |
| @@ -545,7 +545,7 @@ ST_FUNC void save_reg(int r) · 544 unmodified lines | ||
| 545 | 545 | type = &p->type; |
| 546 | 546 | if ((p->r & VT_LVAL) || |
| 547 | 547 | (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG)) |
| 548 | −#ifdef TCC_TARGET_X86_64 | |
| 548 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 549 | 549 | type = &char_pointer_type; |
| 550 | 550 | #else |
| 551 | 551 | type = &int_type; |
| @@ -562,7 +562,7 @@ ST_FUNC void save_reg(int r) · 10 unmodified lines | ||
| 562 | 562 | o(0xd8dd); /* fstp %st(0) */ |
| 563 | 563 | } |
| 564 | 564 | #endif |
| 565 | −#ifndef TCC_TARGET_X86_64 | |
| 565 | +#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64) | |
| 566 | 566 | /* special long long case */ |
| 567 | 567 | if ((type->t & VT_BTYPE) == VT_LLONG) { |
| 568 | 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 | 683 | /* get address of vtop (vtop MUST BE an lvalue) */ |
| 684 | −static void gaddrof(void) | |
| 684 | +ST_FUNC void gaddrof(void) | |
| 685 | 685 | { |
| 686 | 686 | if (vtop->r & VT_REF) |
| 687 | 687 | gv(RC_INT); |
| @@ -803,11 +803,13 @@ ST_FUNC int gv(int rc) · 115 unmodified lines | ||
| 803 | 803 | |
| 804 | 804 | r = vtop->r & VT_VALMASK; |
| 805 | 805 | rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT; |
| 806 | +#ifndef TCC_TARGET_ARM64 | |
| 806 | 807 | if (rc == RC_IRET) |
| 807 | 808 | rc2 = RC_LRET; |
| 808 | 809 | #ifdef TCC_TARGET_X86_64 |
| 809 | 810 | else if (rc == RC_FRET) |
| 810 | 811 | rc2 = RC_QRET; |
| 812 | +#endif | |
| 811 | 813 | #endif |
| 812 | 814 | |
| 813 | 815 | /* need to reload if: |
| @@ -817,7 +819,7 @@ ST_FUNC int gv(int rc) · 3 unmodified lines | ||
| 817 | 819 | if (r >= VT_CONST |
| 818 | 820 | || (vtop->r & VT_LVAL) |
| 819 | 821 | || !(reg_classes[r] & rc) |
| 820 | −#ifdef TCC_TARGET_X86_64 | |
| 822 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 821 | 823 | || ((vtop->type.t & VT_BTYPE) == VT_QLONG && !(reg_classes[vtop->r2] & rc2)) |
| 822 | 824 | || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2)) |
| 823 | 825 | #else |
| @@ -826,7 +828,7 @@ ST_FUNC int gv(int rc) · 2 unmodified lines | ||
| 826 | 828 | ) |
| 827 | 829 | { |
| 828 | 830 | r = get_reg(rc); |
| 829 | −#ifdef TCC_TARGET_X86_64 | |
| 831 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 830 | 832 | if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT)) { |
| 831 | 833 | int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; |
| 832 | 834 | #else |
| @@ -838,7 +840,7 @@ ST_FUNC int gv(int rc) · 5 unmodified lines | ||
| 838 | 840 | original_type = vtop->type.t; |
| 839 | 841 | /* two register type load : expand to two words |
| 840 | 842 | temporarily */ |
| 841 | −#ifndef TCC_TARGET_X86_64 | |
| 843 | +#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64) | |
| 842 | 844 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
| 843 | 845 | /* load constant */ |
| 844 | 846 | ll = vtop->c.ull; |
| @@ -890,7 +892,7 @@ ST_FUNC int gv(int rc) · 45 unmodified lines | ||
| 890 | 892 | t1 = t; |
| 891 | 893 | /* compute memory access type */ |
| 892 | 894 | if (vtop->r & VT_REF) |
| 893 | −#ifdef TCC_TARGET_X86_64 | |
| 895 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 894 | 896 | t = VT_PTR; |
| 895 | 897 | #else |
| 896 | 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 | 958 | /* wrapper around RC_FRET to return a register by type */ |
| 956 | 959 | static int rc_fret(int t) |
| 957 | 960 | { |
| @@ -962,6 +965,7 @@ static int rc_fret(int t) · 4 unmodified lines | ||
| 962 | 965 | #endif |
| 963 | 966 | return RC_FRET; |
| 964 | 967 | } |
| 968 | +#endif | |
| 965 | 969 | |
| 966 | 970 | /* wrapper around REG_FRET to return a register by type */ |
| 967 | 971 | static int reg_fret(int t) |
| @@ -1147,7 +1151,7 @@ ST_FUNC int gvtst(int inv, int t) · 179 unmodified lines | ||
| 1147 | 1151 | return gtst(inv, t); |
| 1148 | 1152 | } |
| 1149 | 1153 | |
| 1150 | −#ifndef TCC_TARGET_X86_64 | |
| 1154 | +#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64) | |
| 1151 | 1155 | /* generate CPU independent (unsigned) long long operations */ |
| 1152 | 1156 | static void gen_opl(int op) |
| 1153 | 1157 | { |
| @@ -1358,7 +1362,7 @@ static void gen_opl(int op) · 204 unmodified lines | ||
| 1358 | 1362 | #elif defined(TCC_TARGET_ARM) |
| 1359 | 1363 | b = ind; |
| 1360 | 1364 | o(0x1A000000 | encbranch(ind, 0, 1)); |
| 1361 | −#elif defined(TCC_TARGET_C67) | |
| 1365 | +#elif defined(TCC_TARGET_C67) || defined(TCC_TARGET_ARM64) | |
| 1362 | 1366 | tcc_error("not implemented"); |
| 1363 | 1367 | #else |
| 1364 | 1368 | #error not supported |
| @@ -1512,7 +1516,8 @@ static void gen_opic(int op) · 147 unmodified lines | ||
| 1512 | 1516 | general_case: |
| 1513 | 1517 | if (!nocode_wanted) { |
| 1514 | 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 | 1521 | gen_opl(op); |
| 1517 | 1522 | else |
| 1518 | 1523 | gen_opi(op); |
| @@ -1679,7 +1684,7 @@ ST_FUNC void gen_op(int op) · 160 unmodified lines | ||
| 1679 | 1684 | if (op >= TOK_ULT && op <= TOK_LOR) { |
| 1680 | 1685 | check_comparison_pointer_types(vtop - 1, vtop, op); |
| 1681 | 1686 | /* pointers are handled are unsigned */ |
| 1682 | −#ifdef TCC_TARGET_X86_64 | |
| 1687 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 1683 | 1688 | t = VT_LLONG | VT_UNSIGNED; |
| 1684 | 1689 | #else |
| 1685 | 1690 | t = VT_INT | VT_UNSIGNED; |
| @@ -1700,7 +1705,7 @@ ST_FUNC void gen_op(int op) · 14 unmodified lines | ||
| 1700 | 1705 | vrott(3); |
| 1701 | 1706 | gen_opic(op); |
| 1702 | 1707 | /* set to integer type */ |
| 1703 | −#ifdef TCC_TARGET_X86_64 | |
| 1708 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 1704 | 1709 | vtop->type.t = VT_LLONG; |
| 1705 | 1710 | #else |
| 1706 | 1711 | vtop->type.t = VT_INT; |
| @@ -1724,7 +1729,7 @@ ST_FUNC void gen_op(int op) · 17 unmodified lines | ||
| 1724 | 1729 | u = pointed_size(&vtop[-1].type); |
| 1725 | 1730 | if (u < 0) |
| 1726 | 1731 | tcc_error("unknown array element size"); |
| 1727 | −#ifdef TCC_TARGET_X86_64 | |
| 1732 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 1728 | 1733 | vpushll(u); |
| 1729 | 1734 | #else |
| 1730 | 1735 | /* XXX: cast to int ? (long long case) */ |
| @@ -1833,6 +1838,9 @@ ST_FUNC void gen_op(int op) · 102 unmodified lines | ||
| 1833 | 1838 | /* generic itof for unsigned long long case */ |
| 1834 | 1839 | static void gen_cvt_itof1(int t) |
| 1835 | 1840 | { |
| 1841 | +#ifdef TCC_TARGET_ARM64 | |
| 1842 | + gen_cvt_itof(t); | |
| 1843 | +#else | |
| 1836 | 1844 | if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == |
| 1837 | 1845 | (VT_LLONG | VT_UNSIGNED)) { |
| 1838 | 1846 | |
| @@ -1851,12 +1859,16 @@ static void gen_cvt_itof1(int t) · 12 unmodified lines | ||
| 1851 | 1859 | } else { |
| 1852 | 1860 | gen_cvt_itof(t); |
| 1853 | 1861 | } |
| 1862 | +#endif | |
| 1854 | 1863 | } |
| 1855 | 1864 | #endif |
| 1856 | 1865 | |
| 1857 | 1866 | /* generic ftoi for unsigned long long case */ |
| 1858 | 1867 | static void gen_cvt_ftoi1(int t) |
| 1859 | 1868 | { |
| 1869 | +#ifdef TCC_TARGET_ARM64 | |
| 1870 | + gen_cvt_ftoi(t); | |
| 1871 | +#else | |
| 1860 | 1872 | int st; |
| 1861 | 1873 | |
| 1862 | 1874 | if (t == (VT_LLONG | VT_UNSIGNED)) { |
| @@ -1878,6 +1890,7 @@ static void gen_cvt_ftoi1(int t) · 15 unmodified lines | ||
| 1878 | 1890 | } else { |
| 1879 | 1891 | gen_cvt_ftoi(t); |
| 1880 | 1892 | } |
| 1893 | +#endif | |
| 1881 | 1894 | } |
| 1882 | 1895 | |
| 1883 | 1896 | /* force char or short cast */ |
| @@ -1968,7 +1981,7 @@ static void gen_cast(CType *type) · 84 unmodified lines | ||
| 1968 | 1981 | vtop->c.ll = vtop->c.ull; |
| 1969 | 1982 | else if (sbt & VT_UNSIGNED) |
| 1970 | 1983 | vtop->c.ll = vtop->c.ui; |
| 1971 | −#ifdef TCC_TARGET_X86_64 | |
| 1984 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 1972 | 1985 | else if (sbt == VT_PTR) |
| 1973 | 1986 | ; |
| 1974 | 1987 | #endif |
| @@ -1979,7 +1992,7 @@ static void gen_cast(CType *type) · 4 unmodified lines | ||
| 1979 | 1992 | vtop->c.ull = vtop->c.ll; |
| 1980 | 1993 | else if (dbt == VT_BOOL) |
| 1981 | 1994 | vtop->c.i = (vtop->c.ll != 0); |
| 1982 | −#ifdef TCC_TARGET_X86_64 | |
| 1995 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 1983 | 1996 | else if (dbt == VT_PTR) |
| 1984 | 1997 | ; |
| 1985 | 1998 | #endif |
| @@ -2024,7 +2037,7 @@ static void gen_cast(CType *type) · 38 unmodified lines | ||
| 2024 | 2037 | gen_cast(type); |
| 2025 | 2038 | } |
| 2026 | 2039 | } |
| 2027 | −#ifndef TCC_TARGET_X86_64 | |
| 2040 | +#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64) | |
| 2028 | 2041 | } else if ((dbt & VT_BTYPE) == VT_LLONG) { |
| 2029 | 2042 | if ((sbt & VT_BTYPE) != VT_LLONG) { |
| 2030 | 2043 | /* scalar to long long */ |
| @@ -2056,11 +2069,18 @@ static void gen_cast(CType *type) · 25 unmodified lines | ||
| 2056 | 2069 | (sbt & VT_BTYPE) != VT_PTR && |
| 2057 | 2070 | (sbt & VT_BTYPE) != VT_FUNC) { |
| 2058 | 2071 | /* need to convert from 32bit to 64bit */ |
| 2059 | − int r = gv(RC_INT); | |
| 2072 | + gv(RC_INT); | |
| 2060 | 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 | 2078 | /* x86_64 specific: movslq */ |
| 2062 | 2079 | o(0x6348); |
| 2063 | 2080 | o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r)); |
| 2081 | +#else | |
| 2082 | +#error | |
| 2083 | +#endif | |
| 2064 | 2084 | } |
| 2065 | 2085 | } |
| 2066 | 2086 | #endif |
| @@ -2589,7 +2609,7 @@ ST_FUNC void vstore(void) · 522 unmodified lines | ||
| 2589 | 2609 | if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { |
| 2590 | 2610 | SValue sv; |
| 2591 | 2611 | t = get_reg(RC_INT); |
| 2592 | −#ifdef TCC_TARGET_X86_64 | |
| 2612 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 2593 | 2613 | sv.type.t = VT_PTR; |
| 2594 | 2614 | #else |
| 2595 | 2615 | sv.type.t = VT_INT; |
| @@ -2600,7 +2620,7 @@ ST_FUNC void vstore(void) · 4 unmodified lines | ||
| 2600 | 2620 | vtop[-1].r = t | VT_LVAL; |
| 2601 | 2621 | } |
| 2602 | 2622 | /* two word case handling : store second register at word + 4 (or +8 for x86-64) */ |
| 2603 | −#ifdef TCC_TARGET_X86_64 | |
| 2623 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 2604 | 2624 | if (((ft & VT_BTYPE) == VT_QLONG) || ((ft & VT_BTYPE) == VT_QFLOAT)) { |
| 2605 | 2625 | int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; |
| 2606 | 2626 | #else |
| @@ -3098,6 +3118,13 @@ static int parse_btype(CType *type, AttributeDef *ad) · 491 unmodified lines | ||
| 3098 | 3118 | goto basic_type1; |
| 3099 | 3119 | } |
| 3100 | 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 | 3128 | case TOK_BOOL: |
| 3102 | 3129 | u = VT_BOOL; |
| 3103 | 3130 | goto basic_type; |
| @@ -3233,7 +3260,8 @@ the_end: · 129 unmodified lines | ||
| 3233 | 3260 | |
| 3234 | 3261 | /* long is never used as type */ |
| 3235 | 3262 | if ((t & VT_BTYPE) == VT_LONG) |
| 3236 | −#if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE | |
| 3263 | +#if (!defined TCC_TARGET_X86_64 && !defined TCC_TARGET_ARM64) || \ | |
| 3264 | + defined TCC_TARGET_PE | |
| 3237 | 3265 | t = (t & ~VT_BTYPE) | VT_INT; |
| 3238 | 3266 | #else |
| 3239 | 3267 | t = (t & ~VT_BTYPE) | VT_LLONG; |
| @@ -3881,6 +3909,36 @@ ST_FUNC void unary(void) · 641 unmodified lines | ||
| 3881 | 3909 | break; |
| 3882 | 3910 | #endif |
| 3883 | 3911 | #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 | 3942 | case TOK_INC: |
| 3885 | 3943 | case TOK_DEC: |
| 3886 | 3944 | t = tok; |
| @@ -4071,6 +4129,15 @@ ST_FUNC void unary(void) · 184 unmodified lines | ||
| 4071 | 4129 | if (!ret_nregs) { |
| 4072 | 4130 | /* get some space for the returned structure */ |
| 4073 | 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 | 4141 | loc = (loc - size) & -align; |
| 4075 | 4142 | ret.type = s->type; |
| 4076 | 4143 | ret.r = VT_LOCAL | VT_LVAL; |
| @@ -4094,12 +4161,14 @@ ST_FUNC void unary(void) · 17 unmodified lines | ||
| 4094 | 4161 | ret.r2 = REG_QRET; |
| 4095 | 4162 | #endif |
| 4096 | 4163 | } else { |
| 4164 | +#ifndef TCC_TARGET_ARM64 | |
| 4097 | 4165 | #ifdef TCC_TARGET_X86_64 |
| 4098 | 4166 | if ((ret.type.t & VT_BTYPE) == VT_QLONG) |
| 4099 | 4167 | #else |
| 4100 | 4168 | if ((ret.type.t & VT_BTYPE) == VT_LLONG) |
| 4101 | 4169 | #endif |
| 4102 | 4170 | ret.r2 = REG_LRET; |
| 4171 | +#endif | |
| 4103 | 4172 | ret.r = REG_IRET; |
| 4104 | 4173 | } |
| 4105 | 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 | 4786 | if (tok != ';') { |
| 4718 | 4787 | gexpr(); |
| 4719 | 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 | 4793 | if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { |
| 4721 | 4794 | CType type, ret_type; |
| 4722 | 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 | 4843 | } else { |
| 4771 | 4844 | gv(RC_IRET); |
| 4772 | 4845 | } |
| 4846 | +#endif | |
| 4773 | 4847 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
| 4774 | 4848 | } |
| 4775 | 4849 | skip(';'); |
| @@ -5160,9 +5234,9 @@ static void init_putv(CType *type, Section *sec, unsigned long c, · 384 unmodified lines | ||
| 5160 | 5234 | /* XXX: generate error if incorrect relocation */ |
| 5161 | 5235 | gen_assign_cast(&dtype); |
| 5162 | 5236 | bt = type->t & VT_BTYPE; |
| 5163 | − /* we'll write at most 12 bytes */ | |
| 5164 | − if (c + 12 > sec->data_allocated) { | |
| 5165 | − section_realloc(sec, c + 12); | |
| 5237 | + /* we'll write at most 16 bytes */ | |
| 5238 | + if (c + 16 > sec->data_allocated) { | |
| 5239 | + section_realloc(sec, c + 16); | |
| 5166 | 5240 | } |
| 5167 | 5241 | ptr = sec->data + c; |
| 5168 | 5242 | /* XXX: make code faster ? */ |
| @@ -5184,6 +5258,9 @@ static void init_putv(CType *type, Section *sec, unsigned long c, · 15 unmodified lines | ||
| 5184 | 5258 | (bt == VT_INT && bit_size != 32))) |
| 5185 | 5259 | tcc_error("initializer element is not computable at load time"); |
| 5186 | 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 | 5264 | case VT_BOOL: |
| 5188 | 5265 | vtop->c.i = (vtop->c.i != 0); |
| 5189 | 5266 | case VT_BYTE: |
| @@ -5203,7 +5280,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c, · 13 unmodified lines | ||
| 5203 | 5280 | break; |
| 5204 | 5281 | case VT_PTR: { |
| 5205 | 5282 | addr_t val = (vtop->c.ptr_offset & bit_mask) << bit_pos; |
| 5206 | −#ifdef TCC_TARGET_X86_64 | |
| 5283 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 5207 | 5284 | if (vtop->r & VT_SYM) |
| 5208 | 5285 | greloca(sec, vtop->sym, c, R_DATA_PTR, val); |
| 5209 | 5286 | else |
| @@ -5217,7 +5294,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c, · 7 unmodified lines | ||
| 5217 | 5294 | } |
| 5218 | 5295 | default: { |
| 5219 | 5296 | int val = (vtop->c.i & bit_mask) << bit_pos; |
| 5220 | −#ifdef TCC_TARGET_X86_64 | |
| 5297 | +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) | |
| 5221 | 5298 | if (vtop->r & VT_SYM) |
| 5222 | 5299 | greloca(sec, vtop->sym, c, R_DATA_PTR, val); |
| 5223 | 5300 | else |
| @@ -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 | + | |
| 610 | +static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level) | |
| 611 | +{ | |
| 612 | + if (level < 0) | |
| 613 | + return -1; | |
| 614 | + else if (level == 0) { | |
| 615 | + *paddr = uc->uc_mcontext.pc; | |
| 616 | + return 0; | |
| 617 | + } | |
| 618 | + else { | |
| 619 | + addr_t *fp = (addr_t *)uc->uc_mcontext.regs[29]; | |
| 620 | + int i; | |
| 621 | + for (i = 1; i < level; i++) | |
| 622 | + fp = (addr_t *)fp[0]; | |
| 623 | + *paddr = fp[1]; | |
| 624 | + return 0; | |
| 625 | + } | |
| 626 | +} | |
| 627 | + | |
| 607 | 628 | /* ------------------------------------------------------------- */ |
| 608 | 629 | #else |
| 609 | 630 | |
| @@ -59,6 +59,10 @@ · 58 unmodified lines | ||
| 59 | 59 | DEF(TOK_ASM2, "__asm") |
| 60 | 60 | DEF(TOK_ASM3, "__asm__") |
| 61 | 61 | |
| 62 | +#ifdef TCC_TARGET_ARM64 | |
| 63 | + DEF(TOK_UINT128, "__uint128_t") | |
| 64 | +#endif | |
| 65 | + | |
| 62 | 66 | /*********************************************************************/ |
| 63 | 67 | /* the following are not keywords. They are included to ease parsing */ |
| 64 | 68 | /* preprocessor only */ |
| @@ -136,6 +140,11 @@ · 71 unmodified lines | ||
| 136 | 140 | DEF(TOK_REGPARM1, "regparm") |
| 137 | 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 | 148 | /* pragma */ |
| 140 | 149 | DEF(TOK_pack, "pack") |
| 141 | 150 | #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) |
| @@ -229,6 +238,30 @@ · 87 unmodified lines | ||
| 229 | 238 | #if defined TCC_TARGET_PE |
| 230 | 239 | DEF(TOK___chkstk, "__chkstk") |
| 231 | 240 | #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 | 266 | /* bound checking symbols */ |
| 234 | 267 | #ifdef CONFIG_TCC_BCHECK |