Unified · Split
| @@ -993,6 +993,32 @@ static int n_func_args(CType *type) · 992 unmodified lines | |||
| 993 | return n_args; | 993 | return n_args; |
| 994 | } | 994 | } |
| 995 | 995 | ||
| 996 | static void arm64_sub_sp(uint64_t diff) | ||
| 997 | { | ||
| 998 | if (!diff) | ||
| 999 | return; | ||
| 1000 | #ifdef TCC_TARGET_PE | ||
| 1001 | if (diff >= 4096) { | ||
| 1002 | Sym *sym = external_helper_sym(TOK___chkstk); | ||
| 1003 | |||
| 1004 | arm64_movimm(15, diff >> 4); | ||
| 1005 | greloca(cur_text_section, sym, ind, R_AARCH64_CALL26, 0); | ||
| 1006 | o(ARM64_BL); // bl __chkstk | ||
| 1007 | o(0xcb2f73ff); // sub sp,sp,x15,lsl #4 | ||
| 1008 | return; | ||
| 1009 | } | ||
| 1010 | #endif | ||
| 1011 | if (!(diff >> 24)) { | ||
| 1012 | if (diff & 0xffful) | ||
| 1013 | o(ARM64_SUB_IMM | ARM64_SF(1) | 0 | ARM64_RN(31) | ARM64_RD(31) | ARM64_IMM12(diff & 0xfff)); | ||
| 1014 | if (diff >> 12) | ||
| 1015 | o(ARM64_SUB_IMM | ARM64_SF(1) | ARM64_SH(1) | ARM64_RN(31) | ARM64_RD(31) | ARM64_IMM12((diff >> 12) & 0xfff)); | ||
| 1016 | } else { | ||
| 1017 | arm64_movimm(16, diff); | ||
| 1018 | o(0xCB3063FFU); // sub sp,sp,x16 | ||
| 1019 | } | ||
| 1020 | } | ||
| 1021 | |||
| 996 | ST_FUNC void gfunc_call(int nb_args) | 1022 | ST_FUNC void gfunc_call(int nb_args) |
| 997 | { | 1023 | { |
| 998 | CType *return_type; | 1024 | CType *return_type; |
| @@ -1039,10 +1065,7 @@ ST_FUNC void gfunc_call(int nb_args) · 40 unmodified lines | |||
| 1039 | 1065 | ||
| 1040 | if (stack >= 0x1000000) // 16Mb | 1066 | if (stack >= 0x1000000) // 16Mb |
| 1041 | tcc_error("stack size too big %lu", stack); | 1067 | tcc_error("stack size too big %lu", stack); |
| 1042 | if (stack & 0xfff) | 1068 | arm64_sub_sp(stack); |
| 1043 | o(0xd10003ff | (stack & 0xfff) << 10); // sub sp,sp,#(n) | ||
| 1044 | if (stack >> 12) | ||
| 1045 | o(0xd14003ff | (stack >> 12) << 10); | ||
| 1046 | 1069 | ||
| 1047 | // First pass: set all values on stack | 1070 | // First pass: set all values on stack |
| 1048 | for (i = nb_args; i; i--) { | 1071 | for (i = nb_args; i; i--) { |
| @@ -1178,6 +1201,9 @@ static int arm64_func_va_list_gr_offs; · 129 unmodified lines | |||
| 1178 | static int arm64_func_va_list_vr_offs; | 1201 | static int arm64_func_va_list_vr_offs; |
| 1179 | static int arm64_func_sub_sp_offset; | 1202 | static int arm64_func_sub_sp_offset; |
| 1180 | 1203 | ||
| 1204 | static unsigned arm64_func_start_offset; | ||
| 1205 | #define ARM64_FUNC_STACK_SETUP_SLOTS 6 | ||
| 1206 | |||
| 1181 | ST_FUNC void gfunc_prolog(Sym *func_sym) | 1207 | ST_FUNC void gfunc_prolog(Sym *func_sym) |
| 1182 | { | 1208 | { |
| 1183 | CType *func_type = &func_sym->type; | 1209 | CType *func_type = &func_sym->type; |
| @@ -1229,6 +1255,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) · 45 unmodified lines | |||
| 1229 | last_int = last_int > 4 ? 4 : last_int; | 1255 | last_int = last_int > 4 ? 4 : last_int; |
| 1230 | last_float = last_float > 4 ? 4 : last_float; | 1256 | last_float = last_float > 4 ? 4 : last_float; |
| 1231 | 1257 | ||
| 1258 | arm64_func_start_offset = ind; | ||
| 1232 | o(0xa9b27bfd); // stp x29,x30,[sp,#-224]! | 1259 | o(0xa9b27bfd); // stp x29,x30,[sp,#-224]! |
| 1233 | for (i = 0; i < last_float; i++) | 1260 | for (i = 0; i < last_float; i++) |
| 1234 | // stp q0,q1,[sp,#16], stp q2,q3,[sp,#48] | 1261 | // stp q0,q1,[sp,#16], stp q2,q3,[sp,#48] |
| @@ -1279,9 +1306,9 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) · 44 unmodified lines | |||
| 1279 | 1306 | ||
| 1280 | o(0x910003fd); // mov x29,sp | 1307 | o(0x910003fd); // mov x29,sp |
| 1281 | arm64_func_sub_sp_offset = ind; | 1308 | arm64_func_sub_sp_offset = ind; |
| 1282 | // In gfunc_epilog these will be replaced with code to decrement SP: | 1309 | /* In gfunc_epilog these will be replaced with stack setup code. */ |
| 1283 | o(0xd503201f); // nop | 1310 | for (i = 0; i < ARM64_FUNC_STACK_SETUP_SLOTS; ++i) |
| 1284 | o(0xd503201f); // nop | 1311 | o(ARM64_NOP); // nop |
| 1285 | loc = 0; | 1312 | loc = 0; |
| 1286 | #ifdef CONFIG_TCC_BCHECK | 1313 | #ifdef CONFIG_TCC_BCHECK |
| 1287 | if (tcc_state->do_bounds_check) | 1314 | if (tcc_state->do_bounds_check) |
| @@ -1478,32 +1505,15 @@ ST_FUNC void gfunc_epilog(void) · 190 unmodified lines | |||
| 1478 | 1505 | ||
| 1479 | if (loc) { | 1506 | if (loc) { |
| 1480 | // Insert instructions to subtract size of stack frame from SP. | 1507 | // Insert instructions to subtract size of stack frame from SP. |
| 1481 | unsigned char *ptr = cur_text_section->data + arm64_func_sub_sp_offset; | 1508 | int i; |
| 1509 | addr_t saved_ind = ind; | ||
| 1510 | addr_t patch_end = arm64_func_sub_sp_offset + ARM64_FUNC_STACK_SETUP_SLOTS * 4; | ||
| 1482 | uint64_t diff = (-loc + 15) & ~15; | 1511 | uint64_t diff = (-loc + 15) & ~15; |
| 1483 | if (!(diff >> 24)) { | 1512 | ind = arm64_func_sub_sp_offset; |
| 1484 | if (diff & 0xfff) // sub sp,sp,#(diff & 0xfff) | 1513 | arm64_sub_sp(diff); |
| 1485 | write32le(ptr, 0xd10003ff | (diff & 0xfff) << 10); | 1514 | for (i = ind; i < patch_end; i += 4) |
| 1486 | if (diff >> 12) // sub sp,sp,#(diff >> 12),lsl #12 | 1515 | write32le(cur_text_section->data + i, ARM64_NOP); // nop |
| 1487 | write32le(ptr + 4, 0xd14003ff | (diff >> 12) << 10); | 1516 | ind = saved_ind; |
| 1488 | } | ||
| 1489 | else { | ||
| 1490 | // In this case we may subtract more than necessary, | ||
| 1491 | // but always less than 17/16 of what we were aiming for. | ||
| 1492 | int i = 0; | ||
| 1493 | int j = 0; | ||
| 1494 | while (diff >> 20) { | ||
| 1495 | diff = (diff + 0xffff) >> 16; | ||
| 1496 | ++i; | ||
| 1497 | } | ||
| 1498 | while (diff >> 16) { | ||
| 1499 | diff = (diff + 1) >> 1; | ||
| 1500 | ++j; | ||
| 1501 | } | ||
| 1502 | write32le(ptr, 0xd2800010 | diff << 5 | i << 21); | ||
| 1503 | // mov x16,#(diff),lsl #(16 * i) | ||
| 1504 | write32le(ptr + 4, 0xcb3063ff | j << 10); | ||
| 1505 | // sub sp,sp,x16,lsl #(j) | ||
| 1506 | } | ||
| 1507 | } | 1517 | } |
| 1508 | o(0x910003bf); // mov sp,x29 | 1518 | o(0x910003bf); // mov sp,x29 |
| 1509 | o(0xa8ce7bfd); // ldp x29,x30,[sp],#224 | 1519 | o(0xa8ce7bfd); // ldp x29,x30,[sp],#224 |