Unified · Split
| @@ -70,6 +70,7 @@ NATIVE_DEFINES_$(CONFIG_arm) += -DTCC_TARGET_ARM · 69 unmodified lines | |||
| 70 | NATIVE_DEFINES_$(CONFIG_arm_eabihf) += -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT | 70 | NATIVE_DEFINES_$(CONFIG_arm_eabihf) += -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT |
| 71 | NATIVE_DEFINES_$(CONFIG_arm_eabi) += -DTCC_ARM_EABI | 71 | NATIVE_DEFINES_$(CONFIG_arm_eabi) += -DTCC_ARM_EABI |
| 72 | NATIVE_DEFINES_$(CONFIG_arm_vfp) += -DTCC_ARM_VFP | 72 | NATIVE_DEFINES_$(CONFIG_arm_vfp) += -DTCC_ARM_VFP |
| 73 | NATIVE_DEFINES_$(CONFIG_arm64) += -DTCC_TARGET_ARM64 | ||
| 73 | NATIVE_DEFINES += $(NATIVE_DEFINES_yes) | 74 | NATIVE_DEFINES += $(NATIVE_DEFINES_yes) |
| 74 | 75 | ||
| 75 | ifeq ($(TOP),.) | 76 | ifeq ($(TOP),.) |
| @@ -86,6 +87,7 @@ ARM_VFP_CROSS = arm-linux-gnu-tcc$(EXESUF) · 10 unmodified lines | |||
| 86 | ARM_EABI_CROSS = arm-linux-gnueabi-tcc$(EXESUF) | 87 | ARM_EABI_CROSS = arm-linux-gnueabi-tcc$(EXESUF) |
| 87 | ARM_EABIHF_CROSS = arm-linux-gnueabihf-tcc$(EXESUF) | 88 | ARM_EABIHF_CROSS = arm-linux-gnueabihf-tcc$(EXESUF) |
| 88 | ARM_CROSS = $(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS) | 89 | ARM_CROSS = $(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS) |
| 90 | ARM64_CROSS = arm64-tcc$(EXESUF) | ||
| 89 | C67_CROSS = c67-tcc$(EXESUF) | 91 | C67_CROSS = c67-tcc$(EXESUF) |
| 90 | 92 | ||
| 91 | # Legacy symlinks for cross compilers | 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 | WINCE_FILES = $(CORE_FILES) arm-gen.c tccpe.c | 109 | WINCE_FILES = $(CORE_FILES) arm-gen.c tccpe.c |
| 108 | X86_64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h | 110 | X86_64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h |
| 109 | ARM_FILES = $(CORE_FILES) arm-gen.c | 111 | ARM_FILES = $(CORE_FILES) arm-gen.c |
| 112 | ARM64_FILES = $(CORE_FILES) arm64-gen.c | ||
| 110 | C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c | 113 | C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c |
| 111 | 114 | ||
| 112 | ifdef CONFIG_WIN64 | 115 | ifdef CONFIG_WIN64 |
| 113 | PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) | 116 | PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) |
| 114 | NATIVE_FILES=$(WIN64_FILES) | 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 | LIBTCC1_CROSS=lib/i386-win32/libtcc1.a | 119 | LIBTCC1_CROSS=lib/i386-win32/libtcc1.a |
| 117 | LIBTCC1=libtcc1.a | 120 | LIBTCC1=libtcc1.a |
| 118 | else ifdef CONFIG_WIN32 | 121 | else ifdef CONFIG_WIN32 |
| 119 | PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) | 122 | PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) |
| 120 | NATIVE_FILES=$(WIN32_FILES) | 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 | LIBTCC1_CROSS=lib/x86_64-win32/libtcc1.a | 125 | LIBTCC1_CROSS=lib/x86_64-win32/libtcc1.a |
| 123 | LIBTCC1=libtcc1.a | 126 | LIBTCC1=libtcc1.a |
| 124 | else ifeq ($(ARCH),i386) | 127 | else ifeq ($(ARCH),i386) |
| 125 | NATIVE_FILES=$(I386_FILES) | 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 | LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a | 130 | LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a |
| 128 | LIBTCC1=libtcc1.a | 131 | LIBTCC1=libtcc1.a |
| 129 | else ifeq ($(ARCH),x86-64) | 132 | else ifeq ($(ARCH),x86-64) |
| 130 | NATIVE_FILES=$(X86_64_FILES) | 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 | LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a | 135 | LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a |
| 133 | LIBTCC1=libtcc1.a | 136 | LIBTCC1=libtcc1.a |
| 134 | else ifeq ($(ARCH),arm) | 137 | else ifeq ($(ARCH),arm) |
| 135 | NATIVE_FILES=$(ARM_FILES) | 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 | LIBTCC1=libtcc1.a | 145 | LIBTCC1=libtcc1.a |
| 138 | LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a | 146 | LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a |
| 139 | endif | 147 | endif |
| @@ -181,6 +189,7 @@ $(ARM_FPA_CROSS): DEFINES = -DTCC_TARGET_ARM · 41 unmodified lines | |||
| 181 | $(ARM_FPA_LD_CROSS)$(EXESUF): DEFINES = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12 | 189 | $(ARM_FPA_LD_CROSS)$(EXESUF): DEFINES = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12 |
| 182 | $(ARM_VFP_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_ARM_VFP -DCONFIG_MULTIARCHDIR="\"arm-linux-gnu\"" | 190 | $(ARM_VFP_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_ARM_VFP -DCONFIG_MULTIARCHDIR="\"arm-linux-gnu\"" |
| 183 | $(ARM_EABI_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_ARM_EABI -DTCC_ARM_VFP -DCONFIG_MULTIARCHDIR="\"arm-linux-gnueabi\"" | 191 | $(ARM_EABI_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_ARM_EABI -DTCC_ARM_VFP -DCONFIG_MULTIARCHDIR="\"arm-linux-gnueabi\"" |
| 192 | $(ARM64_CROSS): DEFINES = -DTCC_TARGET_ARM64 | ||
| 184 | 193 | ||
| 185 | $(I386_CROSS): $(I386_FILES) | 194 | $(I386_CROSS): $(I386_FILES) |
| 186 | $(X64_CROSS): $(X86_64_FILES) | 195 | $(X64_CROSS): $(X86_64_FILES) |
| @@ -189,6 +198,7 @@ $(WIN64_CROSS): $(WIN64_FILES) · 2 unmodified lines | |||
| 189 | $(WINCE_CROSS): $(WINCE_FILES) | 198 | $(WINCE_CROSS): $(WINCE_FILES) |
| 190 | $(C67_CROSS): $(C67_FILES) | 199 | $(C67_CROSS): $(C67_FILES) |
| 191 | $(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS): $(ARM_FILES) | 200 | $(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS): $(ARM_FILES) |
| 201 | $(ARM64_CROSS): $(ARM64_FILES) | ||
| 192 | 202 | ||
| 193 | # libtcc generation and test | 203 | # libtcc generation and test |
| 194 | ifndef ONE_SOURCE | 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 | esac | 99 | esac |
| 100 | cpu="armv4l" | 100 | cpu="armv4l" |
| 101 | ;; | 101 | ;; |
| 102 | aarch64) | ||
| 103 | cpu="aarch64" | ||
| 104 | ;; | ||
| 102 | alpha) | 105 | alpha) |
| 103 | cpu="alpha" | 106 | cpu="alpha" |
| 104 | ;; | 107 | ;; |
| @@ -435,6 +438,9 @@ elif test "$cpu" = "armv4l" ; then · 330 unmodified lines | |||
| 435 | echo "ARCH=arm" >> config.mak | 438 | echo "ARCH=arm" >> config.mak |
| 436 | echo "#define HOST_ARM 1" >> $TMPH | 439 | echo "#define HOST_ARM 1" >> $TMPH |
| 437 | echo "#define TCC_ARM_VERSION $cpuver" >> $TMPH | 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 | elif test "$cpu" = "powerpc" ; then | 444 | elif test "$cpu" = "powerpc" ; then |
| 439 | echo "ARCH=ppc" >> config.mak | 445 | echo "ARCH=ppc" >> config.mak |
| 440 | echo "#define HOST_PPC 1" >> $TMPH | 446 | echo "#define HOST_PPC 1" >> $TMPH |
| @@ -7,6 +7,8 @@ · 6 unmodified lines | |||
| 7 | # define TRIPLET_ARCH "x86_64" | 7 | # define TRIPLET_ARCH "x86_64" |
| 8 | #elif defined(__arm__) | 8 | #elif defined(__arm__) |
| 9 | # define TRIPLET_ARCH "arm" | 9 | # define TRIPLET_ARCH "arm" |
| 10 | #elif defined(__aarch64__) | ||
| 11 | # define TRIPLET_ARCH "aarch64" | ||
| 10 | #else | 12 | #else |
| 11 | # define TRIPLET_ARCH "unknown" | 13 | # define TRIPLET_ARCH "unknown" |
| 12 | #endif | 14 | #endif |
| @@ -2336,6 +2336,117 @@ typedef Elf32_Addr Elf32_Conflict; · 2335 unmodified lines | |||
| 2336 | #define R_AARCH64_NONE 0 /* No relocation. */ | 2336 | #define R_AARCH64_NONE 0 /* No relocation. */ |
| 2337 | #define R_AARCH64_ABS64 257 /* Direct 64 bit. */ | 2337 | #define R_AARCH64_ABS64 257 /* Direct 64 bit. */ |
| 2338 | #define R_AARCH64_ABS32 258 /* Direct 32 bit. */ | 2338 | #define R_AARCH64_ABS32 258 /* Direct 32 bit. */ |
| 2339 | #define R_AARCH64_ABS16 259 /* Direct 16-bit. */ | ||
| 2340 | #define R_AARCH64_PREL64 260 /* PC-relative 64-bit. */ | ||
| 2341 | #define R_AARCH64_PREL32 261 /* PC-relative 32-bit. */ | ||
| 2342 | #define R_AARCH64_PREL16 262 /* PC-relative 16-bit. */ | ||
| 2343 | #define R_AARCH64_MOVW_UABS_G0 263 /* Dir. MOVZ imm. from bits 15:0. */ | ||
| 2344 | #define R_AARCH64_MOVW_UABS_G0_NC 264 /* Likewise for MOVK; no check. */ | ||
| 2345 | #define R_AARCH64_MOVW_UABS_G1 265 /* Dir. MOVZ imm. from bits 31:16. */ | ||
| 2346 | #define R_AARCH64_MOVW_UABS_G1_NC 266 /* Likewise for MOVK; no check. */ | ||
| 2347 | #define R_AARCH64_MOVW_UABS_G2 267 /* Dir. MOVZ imm. from bits 47:32. */ | ||
| 2348 | #define R_AARCH64_MOVW_UABS_G2_NC 268 /* Likewise for MOVK; no check. */ | ||
| 2349 | #define R_AARCH64_MOVW_UABS_G3 269 /* Dir. MOV{K,Z} imm. from 63:48. */ | ||
| 2350 | #define R_AARCH64_MOVW_SABS_G0 270 /* Dir. MOV{N,Z} imm. from 15:0. */ | ||
| 2351 | #define R_AARCH64_MOVW_SABS_G1 271 /* Dir. MOV{N,Z} imm. from 31:16. */ | ||
| 2352 | #define R_AARCH64_MOVW_SABS_G2 272 /* Dir. MOV{N,Z} imm. from 47:32. */ | ||
| 2353 | #define R_AARCH64_LD_PREL_LO19 273 /* PC-rel. LD imm. from bits 20:2. */ | ||
| 2354 | #define R_AARCH64_ADR_PREL_LO21 274 /* PC-rel. ADR imm. from bits 20:0. */ | ||
| 2355 | #define R_AARCH64_ADR_PREL_PG_HI21 275 /* Page-rel. ADRP imm. from 32:12. */ | ||
| 2356 | #define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Likewise; no overflow check. */ | ||
| 2357 | #define R_AARCH64_ADD_ABS_LO12_NC 277 /* Dir. ADD imm. from bits 11:0. */ | ||
| 2358 | #define R_AARCH64_LDST8_ABS_LO12_NC 278 /* Likewise for LD/ST; no check. */ | ||
| 2359 | #define R_AARCH64_TSTBR14 279 /* PC-rel. TBZ/TBNZ imm. from 15:2. */ | ||
| 2360 | #define R_AARCH64_CONDBR19 280 /* PC-rel. cond. br. imm. from 20:2. */ | ||
| 2361 | #define R_AARCH64_JUMP26 282 /* PC-rel. B imm. from bits 27:2. */ | ||
| 2362 | #define R_AARCH64_CALL26 283 /* Likewise for CALL. */ | ||
| 2363 | #define R_AARCH64_LDST16_ABS_LO12_NC 284 /* Dir. ADD imm. from bits 11:1. */ | ||
| 2364 | #define R_AARCH64_LDST32_ABS_LO12_NC 285 /* Likewise for bits 11:2. */ | ||
| 2365 | #define R_AARCH64_LDST64_ABS_LO12_NC 286 /* Likewise for bits 11:3. */ | ||
| 2366 | #define R_AARCH64_MOVW_PREL_G0 287 /* PC-rel. MOV{N,Z} imm. from 15:0. */ | ||
| 2367 | #define R_AARCH64_MOVW_PREL_G0_NC 288 /* Likewise for MOVK; no check. */ | ||
| 2368 | #define R_AARCH64_MOVW_PREL_G1 289 /* PC-rel. MOV{N,Z} imm. from 31:16. */ | ||
| 2369 | #define R_AARCH64_MOVW_PREL_G1_NC 290 /* Likewise for MOVK; no check. */ | ||
| 2370 | #define R_AARCH64_MOVW_PREL_G2 291 /* PC-rel. MOV{N,Z} imm. from 47:32. */ | ||
| 2371 | #define R_AARCH64_MOVW_PREL_G2_NC 292 /* Likewise for MOVK; no check. */ | ||
| 2372 | #define R_AARCH64_MOVW_PREL_G3 293 /* PC-rel. MOV{N,Z} imm. from 63:48. */ | ||
| 2373 | #define R_AARCH64_LDST128_ABS_LO12_NC 299 /* Dir. ADD imm. from bits 11:4. */ | ||
| 2374 | #define R_AARCH64_MOVW_GOTOFF_G0 300 /* GOT-rel. off. MOV{N,Z} imm. 15:0. */ | ||
| 2375 | #define R_AARCH64_MOVW_GOTOFF_G0_NC 301 /* Likewise for MOVK; no check. */ | ||
| 2376 | #define R_AARCH64_MOVW_GOTOFF_G1 302 /* GOT-rel. o. MOV{N,Z} imm. 31:16. */ | ||
| 2377 | #define R_AARCH64_MOVW_GOTOFF_G1_NC 303 /* Likewise for MOVK; no check. */ | ||
| 2378 | #define R_AARCH64_MOVW_GOTOFF_G2 304 /* GOT-rel. o. MOV{N,Z} imm. 47:32. */ | ||
| 2379 | #define R_AARCH64_MOVW_GOTOFF_G2_NC 305 /* Likewise for MOVK; no check. */ | ||
| 2380 | #define R_AARCH64_MOVW_GOTOFF_G3 306 /* GOT-rel. o. MOV{N,Z} imm. 63:48. */ | ||
| 2381 | #define R_AARCH64_GOTREL64 307 /* GOT-relative 64-bit. */ | ||
| 2382 | #define R_AARCH64_GOTREL32 308 /* GOT-relative 32-bit. */ | ||
| 2383 | #define R_AARCH64_GOT_LD_PREL19 309 /* PC-rel. GOT off. load imm. 20:2. */ | ||
| 2384 | #define R_AARCH64_LD64_GOTOFF_LO15 310 /* GOT-rel. off. LD/ST imm. 14:3. */ | ||
| 2385 | #define R_AARCH64_ADR_GOT_PAGE 311 /* P-page-rel. GOT off. ADRP 32:12. */ | ||
| 2386 | #define R_AARCH64_LD64_GOT_LO12_NC 312 /* Dir. GOT off. LD/ST imm. 11:3. */ | ||
| 2387 | #define R_AARCH64_LD64_GOTPAGE_LO15 313 /* GOT-page-rel. GOT off. LD/ST 14:3 */ | ||
| 2388 | #define R_AARCH64_TLSGD_ADR_PREL21 512 /* PC-relative ADR imm. 20:0. */ | ||
| 2389 | #define R_AARCH64_TLSGD_ADR_PAGE21 513 /* page-rel. ADRP imm. 32:12. */ | ||
| 2390 | #define R_AARCH64_TLSGD_ADD_LO12_NC 514 /* direct ADD imm. from 11:0. */ | ||
| 2391 | #define R_AARCH64_TLSGD_MOVW_G1 515 /* GOT-rel. MOV{N,Z} 31:16. */ | ||
| 2392 | #define R_AARCH64_TLSGD_MOVW_G0_NC 516 /* GOT-rel. MOVK imm. 15:0. */ | ||
| 2393 | #define R_AARCH64_TLSLD_ADR_PREL21 517 /* Like 512; local dynamic model. */ | ||
| 2394 | #define R_AARCH64_TLSLD_ADR_PAGE21 518 /* Like 513; local dynamic model. */ | ||
| 2395 | #define R_AARCH64_TLSLD_ADD_LO12_NC 519 /* Like 514; local dynamic model. */ | ||
| 2396 | #define R_AARCH64_TLSLD_MOVW_G1 520 /* Like 515; local dynamic model. */ | ||
| 2397 | #define R_AARCH64_TLSLD_MOVW_G0_NC 521 /* Like 516; local dynamic model. */ | ||
| 2398 | #define R_AARCH64_TLSLD_LD_PREL19 522 /* TLS PC-rel. load imm. 20:2. */ | ||
| 2399 | #define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* TLS DTP-rel. MOV{N,Z} 47:32. */ | ||
| 2400 | #define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* TLS DTP-rel. MOV{N,Z} 31:16. */ | ||
| 2401 | #define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* Likewise; MOVK; no check. */ | ||
| 2402 | #define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* TLS DTP-rel. MOV{N,Z} 15:0. */ | ||
| 2403 | #define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 /* Likewise; MOVK; no check. */ | ||
| 2404 | #define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTP-rel. ADD imm. from 23:12. */ | ||
| 2405 | #define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTP-rel. ADD imm. from 11:0. */ | ||
| 2406 | #define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* Likewise; no ovfl. check. */ | ||
| 2407 | #define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTP-rel. LD/ST imm. 11:0. */ | ||
| 2408 | #define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* Likewise; no check. */ | ||
| 2409 | #define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTP-rel. LD/ST imm. 11:1. */ | ||
| 2410 | #define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* Likewise; no check. */ | ||
| 2411 | #define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTP-rel. LD/ST imm. 11:2. */ | ||
| 2412 | #define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* Likewise; no check. */ | ||
| 2413 | #define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTP-rel. LD/ST imm. 11:3. */ | ||
| 2414 | #define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* Likewise; no check. */ | ||
| 2415 | #define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* GOT-rel. MOV{N,Z} 31:16. */ | ||
| 2416 | #define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* GOT-rel. MOVK 15:0. */ | ||
| 2417 | #define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page-rel. ADRP 32:12. */ | ||
| 2418 | #define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* Direct LD off. 11:3. */ | ||
| 2419 | #define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* PC-rel. load imm. 20:2. */ | ||
| 2420 | #define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TLS TP-rel. MOV{N,Z} 47:32. */ | ||
| 2421 | #define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 /* TLS TP-rel. MOV{N,Z} 31:16. */ | ||
| 2422 | #define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 /* Likewise; MOVK; no check. */ | ||
| 2423 | #define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 /* TLS TP-rel. MOV{N,Z} 15:0. */ | ||
| 2424 | #define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 /* Likewise; MOVK; no check. */ | ||
| 2425 | #define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 /* TP-rel. ADD imm. 23:12. */ | ||
| 2426 | #define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 /* TP-rel. ADD imm. 11:0. */ | ||
| 2427 | #define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 /* Likewise; no ovfl. check. */ | ||
| 2428 | #define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 /* TP-rel. LD/ST off. 11:0. */ | ||
| 2429 | #define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 /* Likewise; no ovfl. check. */ | ||
| 2430 | #define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 /* TP-rel. LD/ST off. 11:1. */ | ||
| 2431 | #define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 /* Likewise; no check. */ | ||
| 2432 | #define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 /* TP-rel. LD/ST off. 11:2. */ | ||
| 2433 | #define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 /* Likewise; no check. */ | ||
| 2434 | #define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 /* TP-rel. LD/ST off. 11:3. */ | ||
| 2435 | #define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 /* Likewise; no check. */ | ||
| 2436 | #define R_AARCH64_TLSDESC_LD_PREL19 560 /* PC-rel. load immediate 20:2. */ | ||
| 2437 | #define R_AARCH64_TLSDESC_ADR_PREL21 561 /* PC-rel. ADR immediate 20:0. */ | ||
| 2438 | #define R_AARCH64_TLSDESC_ADR_PAGE21 562 /* Page-rel. ADRP imm. 32:12. */ | ||
| 2439 | #define R_AARCH64_TLSDESC_LD64_LO12 563 /* Direct LD off. from 11:3. */ | ||
| 2440 | #define R_AARCH64_TLSDESC_ADD_LO12 564 /* Direct ADD imm. from 11:0. */ | ||
| 2441 | #define R_AARCH64_TLSDESC_OFF_G1 565 /* GOT-rel. MOV{N,Z} imm. 31:16. */ | ||
| 2442 | #define R_AARCH64_TLSDESC_OFF_G0_NC 566 /* GOT-rel. MOVK imm. 15:0; no ck. */ | ||
| 2443 | #define R_AARCH64_TLSDESC_LDR 567 /* Relax LDR. */ | ||
| 2444 | #define R_AARCH64_TLSDESC_ADD 568 /* Relax ADD. */ | ||
| 2445 | #define R_AARCH64_TLSDESC_CALL 569 /* Relax BLR. */ | ||
| 2446 | #define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 /* TP-rel. LD/ST off. 11:4. */ | ||
| 2447 | #define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 /* Likewise; no check. */ | ||
| 2448 | #define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 /* DTP-rel. LD/ST imm. 11:4. */ | ||
| 2449 | #define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 /* Likewise; no check. */ | ||
| 2339 | #define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */ | 2450 | #define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */ |
| 2340 | #define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */ | 2451 | #define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */ |
| 2341 | #define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */ | 2452 | #define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */ |
| @@ -2344,6 +2455,7 @@ typedef Elf32_Addr Elf32_Conflict; · 2 unmodified lines | |||
| 2344 | #define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */ | 2455 | #define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */ |
| 2345 | #define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */ | 2456 | #define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */ |
| 2346 | #define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */ | 2457 | #define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */ |
| 2458 | #define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */ | ||
| 2347 | 2459 | ||
| 2348 | /* ARM relocs. */ | 2460 | /* ARM relocs. */ |
| 2349 | 2461 | ||
| @@ -46,6 +46,19 @@ typedef char *va_list; · 45 unmodified lines | |||
| 46 | #define va_copy(dest, src) (dest) = (src) | 46 | #define va_copy(dest, src) (dest) = (src) |
| 47 | #define va_end(ap) | 47 | #define va_end(ap) |
| 48 | 48 | ||
| 49 | #elif defined(__aarch64__) | ||
| 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 | #else /* __i386__ */ | 62 | #else /* __i386__ */ |
| 50 | typedef char *va_list; | 63 | typedef char *va_list; |
| 51 | /* only correct for i386 */ | 64 | /* only correct for i386 */ |
| @@ -28,6 +28,11 @@ ifndef TARGET # native library · 27 unmodified lines | |||
| 28 | ifeq ($(ARCH),arm) | 28 | ifeq ($(ARCH),arm) |
| 29 | TARGET = arm | 29 | TARGET = arm |
| 30 | XCC = $(CC) | 30 | XCC = $(CC) |
| 31 | else | ||
| 32 | ifeq ($(ARCH),arm64) | ||
| 33 | TARGET = arm64 | ||
| 34 | else | ||
| 35 | endif | ||
| 31 | endif | 36 | endif |
| 32 | endif | 37 | endif |
| 33 | endif | 38 | endif |
| @@ -49,6 +54,7 @@ X86_64_O = libtcc1.o alloca86_64.o · 15 unmodified lines | |||
| 49 | ARM_O = libtcc1.o armeabi.o alloca-arm.o | 54 | ARM_O = libtcc1.o armeabi.o alloca-arm.o |
| 50 | WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o | 55 | WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o |
| 51 | WIN64_O = $(X86_64_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o | 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 | # build TCC runtime library to contain PIC code, so it can be linked | 59 | # build TCC runtime library to contain PIC code, so it can be linked |
| 54 | # into shared libraries | 60 | # into shared libraries |
| @@ -86,6 +92,11 @@ ifeq "$(TARGET)" "arm" · 31 unmodified lines | |||
| 86 | OBJ = $(addprefix $(DIR)/,$(ARM_O)) | 92 | OBJ = $(addprefix $(DIR)/,$(ARM_O)) |
| 87 | TGT = -DTCC_TARGET_ARM | 93 | TGT = -DTCC_TARGET_ARM |
| 88 | XCC ?= $(TCC) -B$(TOP) | 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 | else | 100 | else |
| 90 | $(error libtcc1.a not supported on target '$(TARGET)') | 101 | $(error libtcc1.a not supported on target '$(TARGET)') |
| 91 | endif | 102 | endif |
| @@ -93,6 +104,7 @@ endif · 1 unmodified line | |||
| 93 | endif | 104 | endif |
| 94 | endif | 105 | endif |
| 95 | endif | 106 | endif |
| 107 | endif | ||
| 96 | 108 | ||
| 97 | XFLAGS = $(CPPFLAGS) $(CFLAGS) $(PICFLAGS) $(TGT) | 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 | #ifdef TCC_TARGET_ARM | 45 | #ifdef TCC_TARGET_ARM |
| 46 | #include "arm-gen.c" | 46 | #include "arm-gen.c" |
| 47 | #endif | 47 | #endif |
| 48 | #ifdef TCC_TARGET_ARM64 | ||
| 49 | #include "arm64-gen.c" | ||
| 50 | #endif | ||
| 48 | #ifdef TCC_TARGET_C67 | 51 | #ifdef TCC_TARGET_C67 |
| 49 | #include "c67-gen.c" | 52 | #include "c67-gen.c" |
| 50 | #endif | 53 | #endif |
| @@ -959,6 +962,8 @@ LIBTCCAPI TCCState *tcc_new(void) · 908 unmodified lines | |||
| 959 | #else | 962 | #else |
| 960 | s->float_abi = ARM_SOFTFP_FLOAT; | 963 | s->float_abi = ARM_SOFTFP_FLOAT; |
| 961 | #endif | 964 | #endif |
| 965 | #elif defined(TCC_TARGET_ARM64) | ||
| 966 | tcc_define_symbol(s, "__aarch64__", NULL); | ||
| 962 | #endif | 967 | #endif |
| 963 | 968 | ||
| 964 | #ifdef TCC_TARGET_PE | 969 | #ifdef TCC_TARGET_PE |
| @@ -1560,7 +1565,7 @@ static int tcc_set_linker(TCCState *s, const char *option) · 595 unmodified lines | |||
| 1560 | } else if (link_option(option, "oformat=", &p)) { | 1565 | } else if (link_option(option, "oformat=", &p)) { |
| 1561 | #if defined(TCC_TARGET_PE) | 1566 | #if defined(TCC_TARGET_PE) |
| 1562 | if (strstart("pe-", &p)) { | 1567 | if (strstart("pe-", &p)) { |
| 1563 | #elif defined(TCC_TARGET_X86_64) | 1568 | #elif defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 1564 | if (strstart("elf64-", &p)) { | 1569 | if (strstart("elf64-", &p)) { |
| 1565 | #else | 1570 | #else |
| 1566 | if (strstart("elf32-", &p)) { | 1571 | if (strstart("elf32-", &p)) { |
| @@ -203,6 +203,8 @@ static void display_info(TCCState *s, int what) · 202 unmodified lines | |||
| 203 | # endif | 203 | # endif |
| 204 | #elif defined TCC_TARGET_ARM | 204 | #elif defined TCC_TARGET_ARM |
| 205 | "ARM" | 205 | "ARM" |
| 206 | #elif defined TCC_TARGET_ARM64 | ||
| 207 | "AArch64" | ||
| 206 | # ifdef TCC_ARM_HARDFLOAT | 208 | # ifdef TCC_ARM_HARDFLOAT |
| 207 | " Hard Float" | 209 | " Hard Float" |
| 208 | # endif | 210 | # endif |
| @@ -113,7 +113,7 @@ · 112 unmodified lines | |||
| 113 | #endif | 113 | #endif |
| 114 | 114 | ||
| 115 | #include "elf.h" | 115 | #include "elf.h" |
| 116 | #ifdef TCC_TARGET_X86_64 | 116 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 117 | # define ELFCLASSW ELFCLASS64 | 117 | # define ELFCLASSW ELFCLASS64 |
| 118 | # define ElfW(type) Elf##64##_##type | 118 | # define ElfW(type) Elf##64##_##type |
| 119 | # define ELFW(type) ELF##64##_##type | 119 | # define ELFW(type) ELF##64##_##type |
| @@ -151,23 +151,26 @@ · 31 unmodified lines | |||
| 151 | /* target selection */ | 151 | /* target selection */ |
| 152 | /* #define TCC_TARGET_I386 *//* i386 code generator */ | 152 | /* #define TCC_TARGET_I386 *//* i386 code generator */ |
| 153 | /* #define TCC_TARGET_ARM *//* ARMv4 code generator */ | 153 | /* #define TCC_TARGET_ARM *//* ARMv4 code generator */ |
| 154 | /* #define TCC_TARGET_ARM64 *//* ARMv8 code generator */ | ||
| 154 | /* #define TCC_TARGET_C67 *//* TMS320C67xx code generator */ | 155 | /* #define TCC_TARGET_C67 *//* TMS320C67xx code generator */ |
| 155 | /* #define TCC_TARGET_X86_64 *//* x86-64 code generator */ | 156 | /* #define TCC_TARGET_X86_64 *//* x86-64 code generator */ |
| 156 | 157 | ||
| 157 | /* default target is I386 */ | 158 | /* default target is I386 */ |
| 158 | #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \ | 159 | #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \ |
| 159 | !defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64) | 160 | !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \ |
| 161 | !defined(TCC_TARGET_X86_64) | ||
| 160 | #define TCC_TARGET_I386 | 162 | #define TCC_TARGET_I386 |
| 161 | #endif | 163 | #endif |
| 162 | 164 | ||
| 163 | #if !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \ | 165 | #if !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \ |
| 164 | !defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64) && \ | 166 | !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \ |
| 165 | !defined(CONFIG_USE_LIBGCC) | 167 | !defined(TCC_TARGET_X86_64) && !defined(CONFIG_USE_LIBGCC) |
| 166 | #define CONFIG_TCC_BCHECK /* enable bound checking code */ | 168 | #define CONFIG_TCC_BCHECK /* enable bound checking code */ |
| 167 | #endif | 169 | #endif |
| 168 | 170 | ||
| 169 | /* define it to include assembler support */ | 171 | /* define it to include assembler support */ |
| 170 | #if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_C67) | 172 | #if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_ARM64) && \ |
| 173 | !defined(TCC_TARGET_C67) | ||
| 171 | #define CONFIG_TCC_ASM | 174 | #define CONFIG_TCC_ASM |
| 172 | #endif | 175 | #endif |
| 173 | 176 | ||
| @@ -184,6 +187,8 @@ · 10 unmodified lines | |||
| 184 | # define TCC_IS_NATIVE | 187 | # define TCC_IS_NATIVE |
| 185 | # elif defined __arm__ && defined TCC_TARGET_ARM | 188 | # elif defined __arm__ && defined TCC_TARGET_ARM |
| 186 | # define TCC_IS_NATIVE | 189 | # define TCC_IS_NATIVE |
| 190 | # elif defined __aarch64__ && defined TCC_TARGET_ARM64 | ||
| 191 | # define TCC_IS_NATIVE | ||
| 187 | # endif | 192 | # endif |
| 188 | #endif | 193 | #endif |
| 189 | 194 | ||
| @@ -256,6 +261,8 @@ · 66 unmodified lines | |||
| 256 | # define CONFIG_TCC_ELFINTERP "/usr/libexec/ld-elf.so.2" | 261 | # define CONFIG_TCC_ELFINTERP "/usr/libexec/ld-elf.so.2" |
| 257 | # elif defined __GNU__ | 262 | # elif defined __GNU__ |
| 258 | # define CONFIG_TCC_ELFINTERP "/lib/ld.so" | 263 | # define CONFIG_TCC_ELFINTERP "/lib/ld.so" |
| 264 | # elif defined TCC_TARGET_ARM64 | ||
| 265 | # define CONFIG_TCC_ELFINTERP "/lib/ld-linux-aarch64.so.1" | ||
| 259 | # elif defined(TCC_TARGET_X86_64) | 266 | # elif defined(TCC_TARGET_X86_64) |
| 260 | # define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2" | 267 | # define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2" |
| 261 | # elif defined(TCC_UCLIBC) | 268 | # elif defined(TCC_UCLIBC) |
| @@ -290,6 +297,9 @@ · 28 unmodified lines | |||
| 290 | #ifdef TCC_TARGET_ARM | 297 | #ifdef TCC_TARGET_ARM |
| 291 | # include "arm-gen.c" | 298 | # include "arm-gen.c" |
| 292 | #endif | 299 | #endif |
| 300 | #ifdef TCC_TARGET_ARM64 | ||
| 301 | # include "arm64-gen.c" | ||
| 302 | #endif | ||
| 293 | #ifdef TCC_TARGET_C67 | 303 | #ifdef TCC_TARGET_C67 |
| 294 | # include "coff.h" | 304 | # include "coff.h" |
| 295 | # include "c67-gen.c" | 305 | # include "c67-gen.c" |
| @@ -1214,6 +1224,7 @@ ST_FUNC void vpushv(SValue *v); · 918 unmodified lines | |||
| 1214 | ST_FUNC void save_reg(int r); | 1224 | ST_FUNC void save_reg(int r); |
| 1215 | ST_FUNC int get_reg(int rc); | 1225 | ST_FUNC int get_reg(int rc); |
| 1216 | ST_FUNC void save_regs(int n); | 1226 | ST_FUNC void save_regs(int n); |
| 1227 | ST_FUNC void gaddrof(void); | ||
| 1217 | ST_FUNC int gv(int rc); | 1228 | ST_FUNC int gv(int rc); |
| 1218 | ST_FUNC void gv2(int rc1, int rc2); | 1229 | ST_FUNC void gv2(int rc1, int rc2); |
| 1219 | ST_FUNC void vpop(void); | 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 | ST_FUNC void gen_cvt_itof1(int t); | 1368 | ST_FUNC void gen_cvt_itof1(int t); |
| 1358 | #endif | 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 | /* ------------ c67-gen.c ------------ */ | 1380 | /* ------------ c67-gen.c ------------ */ |
| 1361 | #ifdef TCC_TARGET_C67 | 1381 | #ifdef TCC_TARGET_C67 |
| 1362 | #endif | 1382 | #endif |
| @@ -291,7 +291,7 @@ ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, · 290 unmodified lines | |||
| 291 | rel = section_ptr_add(sr, sizeof(ElfW_Rel)); | 291 | rel = section_ptr_add(sr, sizeof(ElfW_Rel)); |
| 292 | rel->r_offset = offset; | 292 | rel->r_offset = offset; |
| 293 | rel->r_info = ELFW(R_INFO)(symbol, type); | 293 | rel->r_info = ELFW(R_INFO)(symbol, type); |
| 294 | #ifdef TCC_TARGET_X86_64 | 294 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 295 | rel->r_addend = addend; | 295 | rel->r_addend = addend; |
| 296 | #else | 296 | #else |
| 297 | if (addend) | 297 | if (addend) |
| @@ -506,7 +506,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 208 unmodified lines | |||
| 506 | sym_index = ELFW(R_SYM)(rel->r_info); | 506 | sym_index = ELFW(R_SYM)(rel->r_info); |
| 507 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | 507 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| 508 | val = sym->st_value; | 508 | val = sym->st_value; |
| 509 | #ifdef TCC_TARGET_X86_64 | 509 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 510 | val += rel->r_addend; | 510 | val += rel->r_addend; |
| 511 | #endif | 511 | #endif |
| 512 | type = ELFW(R_TYPE)(rel->r_info); | 512 | type = ELFW(R_TYPE)(rel->r_info); |
| @@ -760,6 +760,69 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 247 unmodified lines | |||
| 760 | fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n", | 760 | fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n", |
| 761 | type, (unsigned)addr, ptr, (unsigned)val); | 761 | type, (unsigned)addr, ptr, (unsigned)val); |
| 762 | break; | 762 | break; |
| 763 | #elif defined(TCC_TARGET_ARM64) | ||
| 764 | case R_AARCH64_ABS64: | ||
| 765 | *(uint64_t *)ptr = val; | ||
| 766 | break; | ||
| 767 | case R_AARCH64_ABS32: | ||
| 768 | *(uint32_t *)ptr = val; | ||
| 769 | break; | ||
| 770 | case R_AARCH64_MOVW_UABS_G0_NC: | ||
| 771 | *(uint32_t *)ptr = (*(uint32_t *)ptr & 0xffe0001f) | | ||
| 772 | (val & 0xffff) << 5; | ||
| 773 | break; | ||
| 774 | case R_AARCH64_MOVW_UABS_G1_NC: | ||
| 775 | *(uint32_t *)ptr = (*(uint32_t *)ptr & 0xffe0001f) | | ||
| 776 | (val >> 16 & 0xffff) << 5; | ||
| 777 | break; | ||
| 778 | case R_AARCH64_MOVW_UABS_G2_NC: | ||
| 779 | *(uint32_t *)ptr = (*(uint32_t *)ptr & 0xffe0001f) | | ||
| 780 | (val >> 32 & 0xffff) << 5; | ||
| 781 | break; | ||
| 782 | case R_AARCH64_MOVW_UABS_G3: | ||
| 783 | *(uint32_t *)ptr = (*(uint32_t *)ptr & 0xffe0001f) | | ||
| 784 | (val >> 48 & 0xffff) << 5; | ||
| 785 | break; | ||
| 786 | case R_AARCH64_ADR_PREL_PG_HI21: { | ||
| 787 | uint64_t off = (val >> 12) - (addr >> 12); | ||
| 788 | if ((off + ((uint64_t)1 << 20)) >> 21) | ||
| 789 | tcc_error("R_AARCH64_ADR_PREL_PG_HI21 relocation failed"); | ||
| 790 | *(uint32_t *)ptr = (*(uint32_t *)ptr & 0x9f00001f) | | ||
| 791 | (off & 0x1ffffc) << 3 | (off & 3) << 29; | ||
| 792 | break; | ||
| 793 | } | ||
| 794 | case R_AARCH64_ADD_ABS_LO12_NC: | ||
| 795 | *(uint32_t *)ptr = (*(uint32_t *)ptr & 0xffc003ff) | | ||
| 796 | (val & 0xfff) << 10; | ||
| 797 | break; | ||
| 798 | case R_AARCH64_JUMP26: | ||
| 799 | case R_AARCH64_CALL26: | ||
| 800 | if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc) | ||
| 801 | tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed"); | ||
| 802 | *(uint32_t *)ptr = 0x14000000 | (type == R_AARCH64_CALL26) << 31 | | ||
| 803 | ((val - addr) >> 2 & 0x3ffffff); | ||
| 804 | break; | ||
| 805 | case R_AARCH64_ADR_GOT_PAGE: { | ||
| 806 | uint64_t off = | ||
| 807 | (((s1->got->sh_addr + | ||
| 808 | s1->sym_attrs[sym_index].got_offset) >> 12) - (addr >> 12)); | ||
| 809 | if ((off + ((uint64_t)1 << 20)) >> 21) | ||
| 810 | tcc_error("R_AARCH64_ADR_GOT_PAGE relocation failed"); | ||
| 811 | *(uint32_t *)ptr = (*(uint32_t *)ptr & 0x9f00001f) | | ||
| 812 | (off & 0x1ffffc) << 3 | (off & 3) << 29; | ||
| 813 | break; | ||
| 814 | } | ||
| 815 | case R_AARCH64_LD64_GOT_LO12_NC: | ||
| 816 | *(uint32_t *)ptr = (*(uint32_t *)ptr & 0xfff803ff) | | ||
| 817 | ((s1->got->sh_addr + s1->sym_attrs[sym_index].got_offset) | ||
| 818 | & 0xff8) << 7; | ||
| 819 | break; | ||
| 820 | case R_AARCH64_COPY: | ||
| 821 | break; | ||
| 822 | default: | ||
| 823 | fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n", | ||
| 824 | type, (unsigned)addr, ptr, (unsigned)val); | ||
| 825 | break; | ||
| 763 | #elif defined(TCC_TARGET_C67) | 826 | #elif defined(TCC_TARGET_C67) |
| 764 | case R_C60_32: | 827 | case R_C60_32: |
| 765 | *(int *)ptr += val; | 828 | *(int *)ptr += val; |
| @@ -955,7 +1018,7 @@ static void put32(unsigned char *p, uint32_t val) · 189 unmodified lines | |||
| 955 | } | 1018 | } |
| 956 | 1019 | ||
| 957 | #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_ARM) || \ | 1020 | #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_ARM) || \ |
| 958 | defined(TCC_TARGET_X86_64) | 1021 | defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 959 | static uint32_t get32(unsigned char *p) | 1022 | static uint32_t get32(unsigned char *p) |
| 960 | { | 1023 | { |
| 961 | return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); | 1024 | return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); |
| @@ -1014,6 +1077,8 @@ static unsigned long put_got_entry(TCCState *s1, · 52 unmodified lines | |||
| 1014 | (reloc_type == R_386_JMP_SLOT); | 1077 | (reloc_type == R_386_JMP_SLOT); |
| 1015 | #elif defined(TCC_TARGET_ARM) | 1078 | #elif defined(TCC_TARGET_ARM) |
| 1016 | (reloc_type == R_ARM_JUMP_SLOT); | 1079 | (reloc_type == R_ARM_JUMP_SLOT); |
| 1080 | #elif defined(TCC_TARGET_ARM64) | ||
| 1081 | (reloc_type == R_AARCH64_JUMP_SLOT); | ||
| 1017 | #else | 1082 | #else |
| 1018 | 0; | 1083 | 0; |
| 1019 | #endif | 1084 | #endif |
| @@ -1135,6 +1200,24 @@ static unsigned long put_got_entry(TCCState *s1, · 115 unmodified lines | |||
| 1135 | if (sym->st_shndx == SHN_UNDEF) | 1200 | if (sym->st_shndx == SHN_UNDEF) |
| 1136 | offset = plt->data_offset - 16; | 1201 | offset = plt->data_offset - 16; |
| 1137 | } | 1202 | } |
| 1203 | #elif defined(TCC_TARGET_ARM64) | ||
| 1204 | if (need_plt_entry) { | ||
| 1205 | Section *plt; | ||
| 1206 | uint8_t *p; | ||
| 1207 | |||
| 1208 | if (s1->output_type == TCC_OUTPUT_DLL) | ||
| 1209 | tcc_error("DLLs unimplemented!"); | ||
| 1210 | |||
| 1211 | plt = s1->plt; | ||
| 1212 | if (plt->data_offset == 0) | ||
| 1213 | section_ptr_add(plt, 32); | ||
| 1214 | p = section_ptr_add(plt, 16); | ||
| 1215 | put32(p, s1->got->data_offset); | ||
| 1216 | put32(p + 4, (uint64_t)s1->got->data_offset >> 32); | ||
| 1217 | |||
| 1218 | if (sym->st_shndx == SHN_UNDEF) | ||
| 1219 | offset = plt->data_offset - 16; | ||
| 1220 | } | ||
| 1138 | #elif defined(TCC_TARGET_C67) | 1221 | #elif defined(TCC_TARGET_C67) |
| 1139 | if (s1->dynsym) { | 1222 | if (s1->dynsym) { |
| 1140 | tcc_error("C67 got not implemented"); | 1223 | tcc_error("C67 got not implemented"); |
| @@ -1277,6 +1360,18 @@ ST_FUNC void build_got_entries(TCCState *s1) · 136 unmodified lines | |||
| 1277 | put32(p+2, 0x46c0); /* nop */ | 1360 | put32(p+2, 0x46c0); /* nop */ |
| 1278 | put32(p+4, 0xeafffffe); /* b $sym */ | 1361 | put32(p+4, 0xeafffffe); /* b $sym */ |
| 1279 | } | 1362 | } |
| 1363 | #elif defined(TCC_TARGET_ARM64) | ||
| 1364 | //xx Other cases may be required here: | ||
| 1365 | case R_AARCH64_ADR_GOT_PAGE: | ||
| 1366 | case R_AARCH64_LD64_GOT_LO12_NC: | ||
| 1367 | if (!s1->got) | ||
| 1368 | build_got(s1); | ||
| 1369 | sym_index = ELFW(R_SYM)(rel->r_info); | ||
| 1370 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | ||
| 1371 | reloc_type = R_AARCH64_GLOB_DAT; | ||
| 1372 | put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, | ||
| 1373 | sym_index); | ||
| 1374 | break; | ||
| 1280 | #elif defined(TCC_TARGET_C67) | 1375 | #elif defined(TCC_TARGET_C67) |
| 1281 | case R_C60_GOT32: | 1376 | case R_C60_GOT32: |
| 1282 | case R_C60_GOTOFF: | 1377 | case R_C60_GOTOFF: |
| @@ -1796,6 +1891,40 @@ ST_FUNC void relocate_plt(TCCState *s1) · 513 unmodified lines | |||
| 1796 | put32(p + 12, x + get32(p + 12) + s1->plt->data - p); | 1891 | put32(p + 12, x + get32(p + 12) + s1->plt->data - p); |
| 1797 | p += 16; | 1892 | p += 16; |
| 1798 | } | 1893 | } |
| 1894 | #elif defined(TCC_TARGET_ARM64) | ||
| 1895 | uint64_t plt = s1->plt->sh_addr; | ||
| 1896 | uint64_t got = s1->got->sh_addr; | ||
| 1897 | uint64_t off = (got >> 12) - (plt >> 12); | ||
| 1898 | if ((off + ((uint64_t)1 << 20)) >> 21) | ||
| 1899 | tcc_error("Failed relocating PLT"); | ||
| 1900 | put32(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]! | ||
| 1901 | put32(p + 4, (0x90000010 | // adrp x16,... | ||
| 1902 | (off & 0x1ffffc) << 3 | (off & 3) << 29)); | ||
| 1903 | put32(p + 8, (0xf9400211 | // ldr x17,[x16,#...] | ||
| 1904 | (got & 0xff8) << 7)); | ||
| 1905 | put32(p + 12, (0x91000210 | // add x16,x16,#... | ||
| 1906 | (got & 0xfff) << 10)); | ||
| 1907 | put32(p + 16, 0xd61f0220); // br x17 | ||
| 1908 | put32(p + 20, 0xd503201f); // nop | ||
| 1909 | put32(p + 24, 0xd503201f); // nop | ||
| 1910 | put32(p + 28, 0xd503201f); // nop | ||
| 1911 | p += 32; | ||
| 1912 | while (p < p_end) { | ||
| 1913 | uint64_t pc = plt + (p - s1->plt->data); | ||
| 1914 | uint64_t addr = got + | ||
| 1915 | (get32(p) | (uint64_t)get32(p + 4) << 32); | ||
| 1916 | uint32_t off = (addr >> 12) - (pc >> 12); | ||
| 1917 | if ((off + ((uint64_t)1 << 20)) >> 21) | ||
| 1918 | tcc_error("Failed relocating PLT"); | ||
| 1919 | put32(p, (0x90000010 | // adrp x16,... | ||
| 1920 | (off & 0x1ffffc) << 3 | (off & 3) << 29)); | ||
| 1921 | put32(p + 4, (0xf9400211 | // ldr x17,[x16,#...] | ||
| 1922 | (addr & 0xff8) << 7)); | ||
| 1923 | put32(p + 8, (0x91000210 | // add x16,x16,#... | ||
| 1924 | (addr & 0xfff) << 10)); | ||
| 1925 | put32(p + 12, 0xd61f0220); // br x17 | ||
| 1926 | p += 16; | ||
| 1927 | } | ||
| 1799 | #elif defined(TCC_TARGET_C67) | 1928 | #elif defined(TCC_TARGET_C67) |
| 1800 | /* XXX: TODO */ | 1929 | /* XXX: TODO */ |
| 1801 | #else | 1930 | #else |
| @@ -2093,7 +2222,7 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) · 291 unmodified lines | |||
| 2093 | put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); | 2222 | put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); |
| 2094 | put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset); | 2223 | put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset); |
| 2095 | put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym))); | 2224 | put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym))); |
| 2096 | #ifdef TCC_TARGET_X86_64 | 2225 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 2097 | put_dt(dynamic, DT_RELA, dyninf->rel_addr); | 2226 | put_dt(dynamic, DT_RELA, dyninf->rel_addr); |
| 2098 | put_dt(dynamic, DT_RELASZ, dyninf->rel_size); | 2227 | put_dt(dynamic, DT_RELASZ, dyninf->rel_size); |
| 2099 | put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); | 2228 | put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); |
| @@ -545,7 +545,7 @@ ST_FUNC void save_reg(int r) · 544 unmodified lines | |||
| 545 | type = &p->type; | 545 | type = &p->type; |
| 546 | if ((p->r & VT_LVAL) || | 546 | if ((p->r & VT_LVAL) || |
| 547 | (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG)) | 547 | (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG)) |
| 548 | #ifdef TCC_TARGET_X86_64 | 548 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 549 | type = &char_pointer_type; | 549 | type = &char_pointer_type; |
| 550 | #else | 550 | #else |
| 551 | type = &int_type; | 551 | type = &int_type; |
| @@ -562,7 +562,7 @@ ST_FUNC void save_reg(int r) · 10 unmodified lines | |||
| 562 | o(0xd8dd); /* fstp %st(0) */ | 562 | o(0xd8dd); /* fstp %st(0) */ |
| 563 | } | 563 | } |
| 564 | #endif | 564 | #endif |
| 565 | #ifndef TCC_TARGET_X86_64 | 565 | #if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64) |
| 566 | /* special long long case */ | 566 | /* special long long case */ |
| 567 | if ((type->t & VT_BTYPE) == VT_LLONG) { | 567 | if ((type->t & VT_BTYPE) == VT_LLONG) { |
| 568 | sv.c.ul += 4; | 568 | sv.c.ul += 4; |
| @@ -681,7 +681,7 @@ static void move_reg(int r, int s, int t) · 112 unmodified lines | |||
| 681 | } | 681 | } |
| 682 | 682 | ||
| 683 | /* get address of vtop (vtop MUST BE an lvalue) */ | 683 | /* get address of vtop (vtop MUST BE an lvalue) */ |
| 684 | static void gaddrof(void) | 684 | ST_FUNC void gaddrof(void) |
| 685 | { | 685 | { |
| 686 | if (vtop->r & VT_REF) | 686 | if (vtop->r & VT_REF) |
| 687 | gv(RC_INT); | 687 | gv(RC_INT); |
| @@ -803,11 +803,13 @@ ST_FUNC int gv(int rc) · 115 unmodified lines | |||
| 803 | 803 | ||
| 804 | r = vtop->r & VT_VALMASK; | 804 | r = vtop->r & VT_VALMASK; |
| 805 | rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT; | 805 | rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT; |
| 806 | #ifndef TCC_TARGET_ARM64 | ||
| 806 | if (rc == RC_IRET) | 807 | if (rc == RC_IRET) |
| 807 | rc2 = RC_LRET; | 808 | rc2 = RC_LRET; |
| 808 | #ifdef TCC_TARGET_X86_64 | 809 | #ifdef TCC_TARGET_X86_64 |
| 809 | else if (rc == RC_FRET) | 810 | else if (rc == RC_FRET) |
| 810 | rc2 = RC_QRET; | 811 | rc2 = RC_QRET; |
| 812 | #endif | ||
| 811 | #endif | 813 | #endif |
| 812 | 814 | ||
| 813 | /* need to reload if: | 815 | /* need to reload if: |
| @@ -817,7 +819,7 @@ ST_FUNC int gv(int rc) · 3 unmodified lines | |||
| 817 | if (r >= VT_CONST | 819 | if (r >= VT_CONST |
| 818 | || (vtop->r & VT_LVAL) | 820 | || (vtop->r & VT_LVAL) |
| 819 | || !(reg_classes[r] & rc) | 821 | || !(reg_classes[r] & rc) |
| 820 | #ifdef TCC_TARGET_X86_64 | 822 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 821 | || ((vtop->type.t & VT_BTYPE) == VT_QLONG && !(reg_classes[vtop->r2] & rc2)) | 823 | || ((vtop->type.t & VT_BTYPE) == VT_QLONG && !(reg_classes[vtop->r2] & rc2)) |
| 822 | || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2)) | 824 | || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2)) |
| 823 | #else | 825 | #else |
| @@ -826,7 +828,7 @@ ST_FUNC int gv(int rc) · 2 unmodified lines | |||
| 826 | ) | 828 | ) |
| 827 | { | 829 | { |
| 828 | r = get_reg(rc); | 830 | r = get_reg(rc); |
| 829 | #ifdef TCC_TARGET_X86_64 | 831 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 830 | if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT)) { | 832 | if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT)) { |
| 831 | int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; | 833 | int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; |
| 832 | #else | 834 | #else |
| @@ -838,7 +840,7 @@ ST_FUNC int gv(int rc) · 5 unmodified lines | |||
| 838 | original_type = vtop->type.t; | 840 | original_type = vtop->type.t; |
| 839 | /* two register type load : expand to two words | 841 | /* two register type load : expand to two words |
| 840 | temporarily */ | 842 | temporarily */ |
| 841 | #ifndef TCC_TARGET_X86_64 | 843 | #if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64) |
| 842 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { | 844 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
| 843 | /* load constant */ | 845 | /* load constant */ |
| 844 | ll = vtop->c.ull; | 846 | ll = vtop->c.ull; |
| @@ -890,7 +892,7 @@ ST_FUNC int gv(int rc) · 45 unmodified lines | |||
| 890 | t1 = t; | 892 | t1 = t; |
| 891 | /* compute memory access type */ | 893 | /* compute memory access type */ |
| 892 | if (vtop->r & VT_REF) | 894 | if (vtop->r & VT_REF) |
| 893 | #ifdef TCC_TARGET_X86_64 | 895 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 894 | t = VT_PTR; | 896 | t = VT_PTR; |
| 895 | #else | 897 | #else |
| 896 | t = VT_INT; | 898 | t = VT_INT; |
| @@ -952,6 +954,7 @@ ST_FUNC void gv2(int rc1, int rc2) · 55 unmodified lines | |||
| 952 | } | 954 | } |
| 953 | } | 955 | } |
| 954 | 956 | ||
| 957 | #ifndef TCC_TARGET_ARM64 | ||
| 955 | /* wrapper around RC_FRET to return a register by type */ | 958 | /* wrapper around RC_FRET to return a register by type */ |
| 956 | static int rc_fret(int t) | 959 | static int rc_fret(int t) |
| 957 | { | 960 | { |
| @@ -962,6 +965,7 @@ static int rc_fret(int t) · 4 unmodified lines | |||
| 962 | #endif | 965 | #endif |
| 963 | return RC_FRET; | 966 | return RC_FRET; |
| 964 | } | 967 | } |
| 968 | #endif | ||
| 965 | 969 | ||
| 966 | /* wrapper around REG_FRET to return a register by type */ | 970 | /* wrapper around REG_FRET to return a register by type */ |
| 967 | static int reg_fret(int t) | 971 | static int reg_fret(int t) |
| @@ -1147,7 +1151,7 @@ ST_FUNC int gvtst(int inv, int t) · 179 unmodified lines | |||
| 1147 | return gtst(inv, t); | 1151 | return gtst(inv, t); |
| 1148 | } | 1152 | } |
| 1149 | 1153 | ||
| 1150 | #ifndef TCC_TARGET_X86_64 | 1154 | #if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64) |
| 1151 | /* generate CPU independent (unsigned) long long operations */ | 1155 | /* generate CPU independent (unsigned) long long operations */ |
| 1152 | static void gen_opl(int op) | 1156 | static void gen_opl(int op) |
| 1153 | { | 1157 | { |
| @@ -1358,7 +1362,7 @@ static void gen_opl(int op) · 204 unmodified lines | |||
| 1358 | #elif defined(TCC_TARGET_ARM) | 1362 | #elif defined(TCC_TARGET_ARM) |
| 1359 | b = ind; | 1363 | b = ind; |
| 1360 | o(0x1A000000 | encbranch(ind, 0, 1)); | 1364 | o(0x1A000000 | encbranch(ind, 0, 1)); |
| 1361 | #elif defined(TCC_TARGET_C67) | 1365 | #elif defined(TCC_TARGET_C67) || defined(TCC_TARGET_ARM64) |
| 1362 | tcc_error("not implemented"); | 1366 | tcc_error("not implemented"); |
| 1363 | #else | 1367 | #else |
| 1364 | #error not supported | 1368 | #error not supported |
| @@ -1512,7 +1516,8 @@ static void gen_opic(int op) · 147 unmodified lines | |||
| 1512 | general_case: | 1516 | general_case: |
| 1513 | if (!nocode_wanted) { | 1517 | if (!nocode_wanted) { |
| 1514 | /* call low level op generator */ | 1518 | /* call low level op generator */ |
| 1515 | if (t1 == VT_LLONG || t2 == VT_LLONG) | 1519 | if (t1 == VT_LLONG || t2 == VT_LLONG || |
| 1520 | (PTR_SIZE == 8 && (t1 == VT_PTR || t2 == VT_PTR))) | ||
| 1516 | gen_opl(op); | 1521 | gen_opl(op); |
| 1517 | else | 1522 | else |
| 1518 | gen_opi(op); | 1523 | gen_opi(op); |
| @@ -1679,7 +1684,7 @@ ST_FUNC void gen_op(int op) · 160 unmodified lines | |||
| 1679 | if (op >= TOK_ULT && op <= TOK_LOR) { | 1684 | if (op >= TOK_ULT && op <= TOK_LOR) { |
| 1680 | check_comparison_pointer_types(vtop - 1, vtop, op); | 1685 | check_comparison_pointer_types(vtop - 1, vtop, op); |
| 1681 | /* pointers are handled are unsigned */ | 1686 | /* pointers are handled are unsigned */ |
| 1682 | #ifdef TCC_TARGET_X86_64 | 1687 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 1683 | t = VT_LLONG | VT_UNSIGNED; | 1688 | t = VT_LLONG | VT_UNSIGNED; |
| 1684 | #else | 1689 | #else |
| 1685 | t = VT_INT | VT_UNSIGNED; | 1690 | t = VT_INT | VT_UNSIGNED; |
| @@ -1700,7 +1705,7 @@ ST_FUNC void gen_op(int op) · 14 unmodified lines | |||
| 1700 | vrott(3); | 1705 | vrott(3); |
| 1701 | gen_opic(op); | 1706 | gen_opic(op); |
| 1702 | /* set to integer type */ | 1707 | /* set to integer type */ |
| 1703 | #ifdef TCC_TARGET_X86_64 | 1708 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 1704 | vtop->type.t = VT_LLONG; | 1709 | vtop->type.t = VT_LLONG; |
| 1705 | #else | 1710 | #else |
| 1706 | vtop->type.t = VT_INT; | 1711 | vtop->type.t = VT_INT; |
| @@ -1724,7 +1729,7 @@ ST_FUNC void gen_op(int op) · 17 unmodified lines | |||
| 1724 | u = pointed_size(&vtop[-1].type); | 1729 | u = pointed_size(&vtop[-1].type); |
| 1725 | if (u < 0) | 1730 | if (u < 0) |
| 1726 | tcc_error("unknown array element size"); | 1731 | tcc_error("unknown array element size"); |
| 1727 | #ifdef TCC_TARGET_X86_64 | 1732 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 1728 | vpushll(u); | 1733 | vpushll(u); |
| 1729 | #else | 1734 | #else |
| 1730 | /* XXX: cast to int ? (long long case) */ | 1735 | /* XXX: cast to int ? (long long case) */ |
| @@ -1833,6 +1838,9 @@ ST_FUNC void gen_op(int op) · 102 unmodified lines | |||
| 1833 | /* generic itof for unsigned long long case */ | 1838 | /* generic itof for unsigned long long case */ |
| 1834 | static void gen_cvt_itof1(int t) | 1839 | static void gen_cvt_itof1(int t) |
| 1835 | { | 1840 | { |
| 1841 | #ifdef TCC_TARGET_ARM64 | ||
| 1842 | gen_cvt_itof(t); | ||
| 1843 | #else | ||
| 1836 | if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == | 1844 | if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == |
| 1837 | (VT_LLONG | VT_UNSIGNED)) { | 1845 | (VT_LLONG | VT_UNSIGNED)) { |
| 1838 | 1846 | ||
| @@ -1851,12 +1859,16 @@ static void gen_cvt_itof1(int t) · 12 unmodified lines | |||
| 1851 | } else { | 1859 | } else { |
| 1852 | gen_cvt_itof(t); | 1860 | gen_cvt_itof(t); |
| 1853 | } | 1861 | } |
| 1862 | #endif | ||
| 1854 | } | 1863 | } |
| 1855 | #endif | 1864 | #endif |
| 1856 | 1865 | ||
| 1857 | /* generic ftoi for unsigned long long case */ | 1866 | /* generic ftoi for unsigned long long case */ |
| 1858 | static void gen_cvt_ftoi1(int t) | 1867 | static void gen_cvt_ftoi1(int t) |
| 1859 | { | 1868 | { |
| 1869 | #ifdef TCC_TARGET_ARM64 | ||
| 1870 | gen_cvt_ftoi(t); | ||
| 1871 | #else | ||
| 1860 | int st; | 1872 | int st; |
| 1861 | 1873 | ||
| 1862 | if (t == (VT_LLONG | VT_UNSIGNED)) { | 1874 | if (t == (VT_LLONG | VT_UNSIGNED)) { |
| @@ -1878,6 +1890,7 @@ static void gen_cvt_ftoi1(int t) · 15 unmodified lines | |||
| 1878 | } else { | 1890 | } else { |
| 1879 | gen_cvt_ftoi(t); | 1891 | gen_cvt_ftoi(t); |
| 1880 | } | 1892 | } |
| 1893 | #endif | ||
| 1881 | } | 1894 | } |
| 1882 | 1895 | ||
| 1883 | /* force char or short cast */ | 1896 | /* force char or short cast */ |
| @@ -1968,7 +1981,7 @@ static void gen_cast(CType *type) · 84 unmodified lines | |||
| 1968 | vtop->c.ll = vtop->c.ull; | 1981 | vtop->c.ll = vtop->c.ull; |
| 1969 | else if (sbt & VT_UNSIGNED) | 1982 | else if (sbt & VT_UNSIGNED) |
| 1970 | vtop->c.ll = vtop->c.ui; | 1983 | vtop->c.ll = vtop->c.ui; |
| 1971 | #ifdef TCC_TARGET_X86_64 | 1984 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 1972 | else if (sbt == VT_PTR) | 1985 | else if (sbt == VT_PTR) |
| 1973 | ; | 1986 | ; |
| 1974 | #endif | 1987 | #endif |
| @@ -1979,7 +1992,7 @@ static void gen_cast(CType *type) · 4 unmodified lines | |||
| 1979 | vtop->c.ull = vtop->c.ll; | 1992 | vtop->c.ull = vtop->c.ll; |
| 1980 | else if (dbt == VT_BOOL) | 1993 | else if (dbt == VT_BOOL) |
| 1981 | vtop->c.i = (vtop->c.ll != 0); | 1994 | vtop->c.i = (vtop->c.ll != 0); |
| 1982 | #ifdef TCC_TARGET_X86_64 | 1995 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 1983 | else if (dbt == VT_PTR) | 1996 | else if (dbt == VT_PTR) |
| 1984 | ; | 1997 | ; |
| 1985 | #endif | 1998 | #endif |
| @@ -2024,7 +2037,7 @@ static void gen_cast(CType *type) · 38 unmodified lines | |||
| 2024 | gen_cast(type); | 2037 | gen_cast(type); |
| 2025 | } | 2038 | } |
| 2026 | } | 2039 | } |
| 2027 | #ifndef TCC_TARGET_X86_64 | 2040 | #if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64) |
| 2028 | } else if ((dbt & VT_BTYPE) == VT_LLONG) { | 2041 | } else if ((dbt & VT_BTYPE) == VT_LLONG) { |
| 2029 | if ((sbt & VT_BTYPE) != VT_LLONG) { | 2042 | if ((sbt & VT_BTYPE) != VT_LLONG) { |
| 2030 | /* scalar to long long */ | 2043 | /* scalar to long long */ |
| @@ -2056,11 +2069,18 @@ static void gen_cast(CType *type) · 25 unmodified lines | |||
| 2056 | (sbt & VT_BTYPE) != VT_PTR && | 2069 | (sbt & VT_BTYPE) != VT_PTR && |
| 2057 | (sbt & VT_BTYPE) != VT_FUNC) { | 2070 | (sbt & VT_BTYPE) != VT_FUNC) { |
| 2058 | /* need to convert from 32bit to 64bit */ | 2071 | /* need to convert from 32bit to 64bit */ |
| 2059 | int r = gv(RC_INT); | 2072 | gv(RC_INT); |
| 2060 | if (sbt != (VT_INT | VT_UNSIGNED)) { | 2073 | if (sbt != (VT_INT | VT_UNSIGNED)) { |
| 2074 | #if defined(TCC_TARGET_ARM64) | ||
| 2075 | gen_cvt_sxtw(); | ||
| 2076 | #elif defined(TCC_TARGET_X86_64) | ||
| 2077 | int r = gv(RC_INT); | ||
| 2061 | /* x86_64 specific: movslq */ | 2078 | /* x86_64 specific: movslq */ |
| 2062 | o(0x6348); | 2079 | o(0x6348); |
| 2063 | o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r)); | 2080 | o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r)); |
| 2081 | #else | ||
| 2082 | #error | ||
| 2083 | #endif | ||
| 2064 | } | 2084 | } |
| 2065 | } | 2085 | } |
| 2066 | #endif | 2086 | #endif |
| @@ -2589,7 +2609,7 @@ ST_FUNC void vstore(void) · 522 unmodified lines | |||
| 2589 | if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { | 2609 | if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { |
| 2590 | SValue sv; | 2610 | SValue sv; |
| 2591 | t = get_reg(RC_INT); | 2611 | t = get_reg(RC_INT); |
| 2592 | #ifdef TCC_TARGET_X86_64 | 2612 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 2593 | sv.type.t = VT_PTR; | 2613 | sv.type.t = VT_PTR; |
| 2594 | #else | 2614 | #else |
| 2595 | sv.type.t = VT_INT; | 2615 | sv.type.t = VT_INT; |
| @@ -2600,7 +2620,7 @@ ST_FUNC void vstore(void) · 4 unmodified lines | |||
| 2600 | vtop[-1].r = t | VT_LVAL; | 2620 | vtop[-1].r = t | VT_LVAL; |
| 2601 | } | 2621 | } |
| 2602 | /* two word case handling : store second register at word + 4 (or +8 for x86-64) */ | 2622 | /* two word case handling : store second register at word + 4 (or +8 for x86-64) */ |
| 2603 | #ifdef TCC_TARGET_X86_64 | 2623 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 2604 | if (((ft & VT_BTYPE) == VT_QLONG) || ((ft & VT_BTYPE) == VT_QFLOAT)) { | 2624 | if (((ft & VT_BTYPE) == VT_QLONG) || ((ft & VT_BTYPE) == VT_QFLOAT)) { |
| 2605 | int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; | 2625 | int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; |
| 2606 | #else | 2626 | #else |
| @@ -3098,6 +3118,13 @@ static int parse_btype(CType *type, AttributeDef *ad) · 491 unmodified lines | |||
| 3098 | goto basic_type1; | 3118 | goto basic_type1; |
| 3099 | } | 3119 | } |
| 3100 | break; | 3120 | break; |
| 3121 | #ifdef TCC_TARGET_ARM64 | ||
| 3122 | case TOK_UINT128: | ||
| 3123 | /* GCC's __uint128_t appears in some Linux header files. Make it a | ||
| 3124 | synonym for long double to get the size and alignment right. */ | ||
| 3125 | u = VT_LDOUBLE; | ||
| 3126 | goto basic_type; | ||
| 3127 | #endif | ||
| 3101 | case TOK_BOOL: | 3128 | case TOK_BOOL: |
| 3102 | u = VT_BOOL; | 3129 | u = VT_BOOL; |
| 3103 | goto basic_type; | 3130 | goto basic_type; |
| @@ -3233,7 +3260,8 @@ the_end: · 129 unmodified lines | |||
| 3233 | 3260 | ||
| 3234 | /* long is never used as type */ | 3261 | /* long is never used as type */ |
| 3235 | if ((t & VT_BTYPE) == VT_LONG) | 3262 | if ((t & VT_BTYPE) == VT_LONG) |
| 3236 | #if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE | 3263 | #if (!defined TCC_TARGET_X86_64 && !defined TCC_TARGET_ARM64) || \ |
| 3264 | defined TCC_TARGET_PE | ||
| 3237 | t = (t & ~VT_BTYPE) | VT_INT; | 3265 | t = (t & ~VT_BTYPE) | VT_INT; |
| 3238 | #else | 3266 | #else |
| 3239 | t = (t & ~VT_BTYPE) | VT_LLONG; | 3267 | t = (t & ~VT_BTYPE) | VT_LLONG; |
| @@ -3881,6 +3909,36 @@ ST_FUNC void unary(void) · 641 unmodified lines | |||
| 3881 | break; | 3909 | break; |
| 3882 | #endif | 3910 | #endif |
| 3883 | #endif | 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 | case TOK_INC: | 3942 | case TOK_INC: |
| 3885 | case TOK_DEC: | 3943 | case TOK_DEC: |
| 3886 | t = tok; | 3944 | t = tok; |
| @@ -4071,6 +4129,15 @@ ST_FUNC void unary(void) · 184 unmodified lines | |||
| 4071 | if (!ret_nregs) { | 4129 | if (!ret_nregs) { |
| 4072 | /* get some space for the returned structure */ | 4130 | /* get some space for the returned structure */ |
| 4073 | size = type_size(&s->type, &align); | 4131 | size = type_size(&s->type, &align); |
| 4132 | #ifdef TCC_TARGET_ARM64 | ||
| 4133 | /* On arm64, a small struct is return in registers. | ||
| 4134 | It is much easier to write it to memory if we know | ||
| 4135 | that we are allowed to write some extra bytes, so | ||
| 4136 | round the allocated space up to a power of 2: */ | ||
| 4137 | if (size < 16) | ||
| 4138 | while (size & (size - 1)) | ||
| 4139 | size = (size | (size - 1)) + 1; | ||
| 4140 | #endif | ||
| 4074 | loc = (loc - size) & -align; | 4141 | loc = (loc - size) & -align; |
| 4075 | ret.type = s->type; | 4142 | ret.type = s->type; |
| 4076 | ret.r = VT_LOCAL | VT_LVAL; | 4143 | ret.r = VT_LOCAL | VT_LVAL; |
| @@ -4094,12 +4161,14 @@ ST_FUNC void unary(void) · 17 unmodified lines | |||
| 4094 | ret.r2 = REG_QRET; | 4161 | ret.r2 = REG_QRET; |
| 4095 | #endif | 4162 | #endif |
| 4096 | } else { | 4163 | } else { |
| 4164 | #ifndef TCC_TARGET_ARM64 | ||
| 4097 | #ifdef TCC_TARGET_X86_64 | 4165 | #ifdef TCC_TARGET_X86_64 |
| 4098 | if ((ret.type.t & VT_BTYPE) == VT_QLONG) | 4166 | if ((ret.type.t & VT_BTYPE) == VT_QLONG) |
| 4099 | #else | 4167 | #else |
| 4100 | if ((ret.type.t & VT_BTYPE) == VT_LLONG) | 4168 | if ((ret.type.t & VT_BTYPE) == VT_LLONG) |
| 4101 | #endif | 4169 | #endif |
| 4102 | ret.r2 = REG_LRET; | 4170 | ret.r2 = REG_LRET; |
| 4171 | #endif | ||
| 4103 | ret.r = REG_IRET; | 4172 | ret.r = REG_IRET; |
| 4104 | } | 4173 | } |
| 4105 | ret.c.i = 0; | 4174 | ret.c.i = 0; |
| @@ -4717,6 +4786,10 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 611 unmodified lines | |||
| 4717 | if (tok != ';') { | 4786 | if (tok != ';') { |
| 4718 | gexpr(); | 4787 | gexpr(); |
| 4719 | gen_assign_cast(&func_vt); | 4788 | gen_assign_cast(&func_vt); |
| 4789 | #ifdef TCC_TARGET_ARM64 | ||
| 4790 | // Perhaps it would be better to use this for all backends: | ||
| 4791 | greturn(); | ||
| 4792 | #else | ||
| 4720 | if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { | 4793 | if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { |
| 4721 | CType type, ret_type; | 4794 | CType type, ret_type; |
| 4722 | int ret_align, ret_nregs; | 4795 | int ret_align, ret_nregs; |
| @@ -4770,6 +4843,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 47 unmodified lines | |||
| 4770 | } else { | 4843 | } else { |
| 4771 | gv(RC_IRET); | 4844 | gv(RC_IRET); |
| 4772 | } | 4845 | } |
| 4846 | #endif | ||
| 4773 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ | 4847 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
| 4774 | } | 4848 | } |
| 4775 | skip(';'); | 4849 | skip(';'); |
| @@ -5160,9 +5234,9 @@ static void init_putv(CType *type, Section *sec, unsigned long c, · 384 unmodified lines | |||
| 5160 | /* XXX: generate error if incorrect relocation */ | 5234 | /* XXX: generate error if incorrect relocation */ |
| 5161 | gen_assign_cast(&dtype); | 5235 | gen_assign_cast(&dtype); |
| 5162 | bt = type->t & VT_BTYPE; | 5236 | bt = type->t & VT_BTYPE; |
| 5163 | /* we'll write at most 12 bytes */ | 5237 | /* we'll write at most 16 bytes */ |
| 5164 | if (c + 12 > sec->data_allocated) { | 5238 | if (c + 16 > sec->data_allocated) { |
| 5165 | section_realloc(sec, c + 12); | 5239 | section_realloc(sec, c + 16); |
| 5166 | } | 5240 | } |
| 5167 | ptr = sec->data + c; | 5241 | ptr = sec->data + c; |
| 5168 | /* XXX: make code faster ? */ | 5242 | /* XXX: make code faster ? */ |
| @@ -5184,6 +5258,9 @@ static void init_putv(CType *type, Section *sec, unsigned long c, · 15 unmodified lines | |||
| 5184 | (bt == VT_INT && bit_size != 32))) | 5258 | (bt == VT_INT && bit_size != 32))) |
| 5185 | tcc_error("initializer element is not computable at load time"); | 5259 | tcc_error("initializer element is not computable at load time"); |
| 5186 | switch(bt) { | 5260 | switch(bt) { |
| 5261 | /* XXX: when cross-compiling we assume that each type has the | ||
| 5262 | same representation on host and target, which is likely to | ||
| 5263 | be wrong in the case of long double */ | ||
| 5187 | case VT_BOOL: | 5264 | case VT_BOOL: |
| 5188 | vtop->c.i = (vtop->c.i != 0); | 5265 | vtop->c.i = (vtop->c.i != 0); |
| 5189 | case VT_BYTE: | 5266 | case VT_BYTE: |
| @@ -5203,7 +5280,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c, · 13 unmodified lines | |||
| 5203 | break; | 5280 | break; |
| 5204 | case VT_PTR: { | 5281 | case VT_PTR: { |
| 5205 | addr_t val = (vtop->c.ptr_offset & bit_mask) << bit_pos; | 5282 | addr_t val = (vtop->c.ptr_offset & bit_mask) << bit_pos; |
| 5206 | #ifdef TCC_TARGET_X86_64 | 5283 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 5207 | if (vtop->r & VT_SYM) | 5284 | if (vtop->r & VT_SYM) |
| 5208 | greloca(sec, vtop->sym, c, R_DATA_PTR, val); | 5285 | greloca(sec, vtop->sym, c, R_DATA_PTR, val); |
| 5209 | else | 5286 | else |
| @@ -5217,7 +5294,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c, · 7 unmodified lines | |||
| 5217 | } | 5294 | } |
| 5218 | default: { | 5295 | default: { |
| 5219 | int val = (vtop->c.i & bit_mask) << bit_pos; | 5296 | int val = (vtop->c.i & bit_mask) << bit_pos; |
| 5220 | #ifdef TCC_TARGET_X86_64 | 5297 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
| 5221 | if (vtop->r & VT_SYM) | 5298 | if (vtop->r & VT_SYM) |
| 5222 | greloca(sec, vtop->sym, c, R_DATA_PTR, val); | 5299 | greloca(sec, vtop->sym, c, R_DATA_PTR, val); |
| 5223 | else | 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 | #else | 629 | #else |
| 609 | 630 | ||
| @@ -59,6 +59,10 @@ · 58 unmodified lines | |||
| 59 | DEF(TOK_ASM2, "__asm") | 59 | DEF(TOK_ASM2, "__asm") |
| 60 | DEF(TOK_ASM3, "__asm__") | 60 | DEF(TOK_ASM3, "__asm__") |
| 61 | 61 | ||
| 62 | #ifdef TCC_TARGET_ARM64 | ||
| 63 | DEF(TOK_UINT128, "__uint128_t") | ||
| 64 | #endif | ||
| 65 | |||
| 62 | /*********************************************************************/ | 66 | /*********************************************************************/ |
| 63 | /* the following are not keywords. They are included to ease parsing */ | 67 | /* the following are not keywords. They are included to ease parsing */ |
| 64 | /* preprocessor only */ | 68 | /* preprocessor only */ |
| @@ -136,6 +140,11 @@ · 71 unmodified lines | |||
| 136 | DEF(TOK_REGPARM1, "regparm") | 140 | DEF(TOK_REGPARM1, "regparm") |
| 137 | DEF(TOK_REGPARM2, "__regparm__") | 141 | DEF(TOK_REGPARM2, "__regparm__") |
| 138 | 142 | ||
| 143 | #ifdef TCC_TARGET_ARM64 | ||
| 144 | DEF(TOK___va_start, "__va_start") | ||
| 145 | DEF(TOK___va_arg, "__va_arg") | ||
| 146 | #endif | ||
| 147 | |||
| 139 | /* pragma */ | 148 | /* pragma */ |
| 140 | DEF(TOK_pack, "pack") | 149 | DEF(TOK_pack, "pack") |
| 141 | #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) | 150 | #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) |
| @@ -229,6 +238,30 @@ · 87 unmodified lines | |||
| 229 | #if defined TCC_TARGET_PE | 238 | #if defined TCC_TARGET_PE |
| 230 | DEF(TOK___chkstk, "__chkstk") | 239 | DEF(TOK___chkstk, "__chkstk") |
| 231 | #endif | 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 | /* bound checking symbols */ | 266 | /* bound checking symbols */ |
| 234 | #ifdef CONFIG_TCC_BCHECK | 267 | #ifdef CONFIG_TCC_BCHECK |