Unified · Split
| @@ -993,6 +993,32 @@ static int n_func_args(CType *type) · 992 unmodified lines | ||
| 993 | 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 | 1022 | ST_FUNC void gfunc_call(int nb_args) |
| 997 | 1023 | { |
| 998 | 1024 | CType *return_type; |
| @@ -1039,10 +1065,7 @@ ST_FUNC void gfunc_call(int nb_args) · 40 unmodified lines | ||
| 1039 | 1065 | |
| 1040 | 1066 | if (stack >= 0x1000000) // 16Mb |
| 1041 | 1067 | tcc_error("stack size too big %lu", stack); |
| 1042 | − if (stack & 0xfff) | |
| 1043 | − o(0xd10003ff | (stack & 0xfff) << 10); // sub sp,sp,#(n) | |
| 1044 | − if (stack >> 12) | |
| 1045 | − o(0xd14003ff | (stack >> 12) << 10); | |
| 1068 | + arm64_sub_sp(stack); | |
| 1046 | 1069 | |
| 1047 | 1070 | // First pass: set all values on stack |
| 1048 | 1071 | for (i = nb_args; i; i--) { |
| @@ -1178,6 +1201,9 @@ static int arm64_func_va_list_gr_offs; · 129 unmodified lines | ||
| 1178 | 1201 | static int arm64_func_va_list_vr_offs; |
| 1179 | 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 | 1207 | ST_FUNC void gfunc_prolog(Sym *func_sym) |
| 1182 | 1208 | { |
| 1183 | 1209 | CType *func_type = &func_sym->type; |
| @@ -1229,6 +1255,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) · 45 unmodified lines | ||
| 1229 | 1255 | last_int = last_int > 4 ? 4 : last_int; |
| 1230 | 1256 | last_float = last_float > 4 ? 4 : last_float; |
| 1231 | 1257 | |
| 1258 | + arm64_func_start_offset = ind; | |
| 1232 | 1259 | o(0xa9b27bfd); // stp x29,x30,[sp,#-224]! |
| 1233 | 1260 | for (i = 0; i < last_float; i++) |
| 1234 | 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 | 1307 | o(0x910003fd); // mov x29,sp |
| 1281 | 1308 | arm64_func_sub_sp_offset = ind; |
| 1282 | − // In gfunc_epilog these will be replaced with code to decrement SP: | |
| 1283 | − o(0xd503201f); // nop | |
| 1284 | − o(0xd503201f); // nop | |
| 1309 | + /* In gfunc_epilog these will be replaced with stack setup code. */ | |
| 1310 | + for (i = 0; i < ARM64_FUNC_STACK_SETUP_SLOTS; ++i) | |
| 1311 | + o(ARM64_NOP); // nop | |
| 1285 | 1312 | loc = 0; |
| 1286 | 1313 | #ifdef CONFIG_TCC_BCHECK |
| 1287 | 1314 | if (tcc_state->do_bounds_check) |
| @@ -1478,32 +1505,15 @@ ST_FUNC void gfunc_epilog(void) · 190 unmodified lines | ||
| 1478 | 1505 | |
| 1479 | 1506 | if (loc) { |
| 1480 | 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 | 1511 | uint64_t diff = (-loc + 15) & ~15; |
| 1483 | − if (!(diff >> 24)) { | |
| 1484 | − if (diff & 0xfff) // sub sp,sp,#(diff & 0xfff) | |
| 1485 | − write32le(ptr, 0xd10003ff | (diff & 0xfff) << 10); | |
| 1486 | − if (diff >> 12) // sub sp,sp,#(diff >> 12),lsl #12 | |
| 1487 | − write32le(ptr + 4, 0xd14003ff | (diff >> 12) << 10); | |
| 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 | − } | |
| 1512 | + ind = arm64_func_sub_sp_offset; | |
| 1513 | + arm64_sub_sp(diff); | |
| 1514 | + for (i = ind; i < patch_end; i += 4) | |
| 1515 | + write32le(cur_text_section->data + i, ARM64_NOP); // nop | |
| 1516 | + ind = saved_ind; | |
| 1507 | 1517 | } |
| 1508 | 1518 | o(0x910003bf); // mov sp,x29 |
| 1509 | 1519 | o(0xa8ce7bfd); // ldp x29,x30,[sp],#224 |