This makes attribute cleanup code work the same as gcc and also makes bound checking a very little bit faster. tcc.h: Add save_return_reg(CType *) and restore_return_reg(CType *) Change gfunc_epilog() to gfunc_epilog(Sym *) arm-gen.c: arm64-gen.c: c67-gen.c: i386-gen.c: il-gen.c: riscv64-gen.c: x86_64-gen.c: Move save and restore register around bound_local_delete call to save_return_reg and restore_return_reg. Pass func_type from gfunc_epilog to gen_bounds_epilog. tccgen.c: Call save_return_reg/restore_return_reg in try_call_scope_cleanup when RETURN is found. tccrun.c: Fix warning when bound checking not used. tests/tests2/101_cleanup.c tests/tests2/101_cleanup.expect Extra checks attribute cleanup save/restore registers. tests/tests2/Makefile: Fix when bound checking not used.
Unified · Split
| @@ -837,6 +837,32 @@ static void gcall_or_jmp(int is_jmp) · 836 unmodified lines | |||
| 837 | } | 837 | } |
| 838 | } | 838 | } |
| 839 | 839 | ||
| 840 | ST_FUNC void save_return_reg(CType *func_type) | ||
| 841 | { | ||
| 842 | int freg = is_float(func_type->t & VT_BTYPE); | ||
| 843 | int ireg = !freg; | ||
| 844 | |||
| 845 | if ((func_type->t & VT_BTYPE) == VT_STRUCT) | ||
| 846 | ireg = freg = 1; | ||
| 847 | if (ireg) | ||
| 848 | o(0xe92d0003); /* push {r0,r1} */ | ||
| 849 | if (freg) | ||
| 850 | o(0xed2d0b04); /* vpush {d0,d1} */ | ||
| 851 | } | ||
| 852 | |||
| 853 | ST_FUNC void restore_return_reg(CType *func_type) | ||
| 854 | { | ||
| 855 | int freg = is_float(func_type->t & VT_BTYPE); | ||
| 856 | int ireg = !freg; | ||
| 857 | |||
| 858 | if ((func_type->t & VT_BTYPE) == VT_STRUCT) | ||
| 859 | ireg = freg = 1; | ||
| 860 | if (freg) | ||
| 861 | o(0xecbd0b04); /* vpop {d0,d1} */ | ||
| 862 | if (ireg) | ||
| 863 | o(0xe8bd0003); /* pop {r0,r1} */ | ||
| 864 | } | ||
| 865 | |||
| 840 | #if defined(CONFIG_TCC_BCHECK) | 866 | #if defined(CONFIG_TCC_BCHECK) |
| 841 | 867 | ||
| 842 | static void gen_bounds_call(int v) | 868 | static void gen_bounds_call(int v) |
| @@ -860,12 +886,13 @@ static void gen_bounds_prolog(void) · 17 unmodified lines | |||
| 860 | o(0xe1a00000); /* call __bound_local_new */ | 886 | o(0xe1a00000); /* call __bound_local_new */ |
| 861 | } | 887 | } |
| 862 | 888 | ||
| 863 | static void gen_bounds_epilog(void) | 889 | static void gen_bounds_epilog(Sym *func_sym) |
| 864 | { | 890 | { |
| 865 | addr_t saved_ind; | 891 | addr_t saved_ind; |
| 866 | addr_t *bounds_ptr; | 892 | addr_t *bounds_ptr; |
| 867 | Sym *sym_data; | 893 | Sym *sym_data; |
| 868 | int offset_modified = func_bound_offset != lbounds_section->data_offset; | 894 | int offset_modified = func_bound_offset != lbounds_section->data_offset; |
| 895 | CType *func_type = &func_sym->type.ref->type; | ||
| 869 | 896 | ||
| 870 | if (!offset_modified && !func_bound_add_epilog) | 897 | if (!offset_modified && !func_bound_add_epilog) |
| 871 | return; | 898 | return; |
| @@ -891,16 +918,16 @@ static void gen_bounds_epilog(void) · 19 unmodified lines | |||
| 891 | } | 918 | } |
| 892 | 919 | ||
| 893 | /* generate bound check local freeing */ | 920 | /* generate bound check local freeing */ |
| 894 | o(0xe92d0003); /* push {r0,r1} */ | 921 | if (func_type->t != VT_VOID) |
| 895 | o(0xed2d0b04); /* vpush {d0,d1} */ | 922 | save_return_reg(func_type); |
| 896 | o(0xe59f0000); /* ldr r0, [pc] */ | 923 | o(0xe59f0000); /* ldr r0, [pc] */ |
| 897 | o(0xea000000); /* b $+4 */ | 924 | o(0xea000000); /* b $+4 */ |
| 898 | greloc(cur_text_section, sym_data, ind, R_ARM_REL32); | 925 | greloc(cur_text_section, sym_data, ind, R_ARM_REL32); |
| 899 | o(-12); /* lbounds_section->data_offset */ | 926 | o(-12); /* lbounds_section->data_offset */ |
| 900 | o(0xe080000f); /* add r0,r0,pc */ | 927 | o(0xe080000f); /* add r0,r0,pc */ |
| 901 | gen_bounds_call(TOK___bound_local_delete); | 928 | gen_bounds_call(TOK___bound_local_delete); |
| 902 | o(0xecbd0b04); /* vpop {d0,d1} */ | 929 | if (func_type->t != VT_VOID) |
| 903 | o(0xe8bd0003); /* pop {r0,r1} */ | 930 | restore_return_reg(func_type); |
| 904 | } | 931 | } |
| 905 | #endif | 932 | #endif |
| 906 | 933 | ||
| @@ -1508,15 +1535,17 @@ from_stack: · 601 unmodified lines | |||
| 1508 | } | 1535 | } |
| 1509 | 1536 | ||
| 1510 | /* generate function epilog */ | 1537 | /* generate function epilog */ |
| 1511 | void gfunc_epilog(void) | 1538 | void gfunc_epilog(Sym *func_sym) |
| 1512 | { | 1539 | { |
| 1513 | uint32_t x; | 1540 | uint32_t x; |
| 1514 | int diff; | 1541 | int diff; |
| 1515 | 1542 | ||
| 1516 | #ifdef CONFIG_TCC_BCHECK | 1543 | #ifdef CONFIG_TCC_BCHECK |
| 1517 | if (tcc_state->do_bounds_check) | 1544 | if (tcc_state->do_bounds_check) |
| 1518 | gen_bounds_epilog(); | 1545 | gen_bounds_epilog(func_sym); |
| 1519 | #endif | 1546 | #endif |
| 1547 | func_sym = NULL; | ||
| 1548 | |||
| 1520 | /* Copy float return value to core register if base standard is used and | 1549 | /* Copy float return value to core register if base standard is used and |
| 1521 | float computation is made with VFP */ | 1550 | float computation is made with VFP */ |
| 1522 | #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) | 1551 | #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) |
| @@ -674,6 +674,32 @@ static void arm64_gen_bl_or_b(int b) · 673 unmodified lines | |||
| 674 | } | 674 | } |
| 675 | } | 675 | } |
| 676 | 676 | ||
| 677 | ST_FUNC void save_return_reg(CType *func_type) | ||
| 678 | { | ||
| 679 | int freg = is_float(func_type->t & VT_BTYPE); | ||
| 680 | int ireg = !freg; | ||
| 681 | |||
| 682 | if ((func_type->t & VT_BTYPE) == VT_STRUCT) | ||
| 683 | ireg = freg = 1; | ||
| 684 | if (ireg) | ||
| 685 | o(0xa9bf07e0); /* stp x0, x1, [sp, #-16]! */ | ||
| 686 | if (freg) | ||
| 687 | o(0xadbf07e0); /* stp q0, q1, [sp, #-32]! */ | ||
| 688 | } | ||
| 689 | |||
| 690 | ST_FUNC void restore_return_reg(CType *func_type) | ||
| 691 | { | ||
| 692 | int freg = is_float(func_type->t & VT_BTYPE); | ||
| 693 | int ireg = !freg; | ||
| 694 | |||
| 695 | if ((func_type->t & VT_BTYPE) == VT_STRUCT) | ||
| 696 | ireg = freg = 1; | ||
| 697 | if (freg) | ||
| 698 | o(0xacc107e0); /* ldp q0, q1, [sp], #32 */ | ||
| 699 | if (ireg) | ||
| 700 | o(0xa8c107e0); /* ldp x0, x1, [sp], #16 */ | ||
| 701 | } | ||
| 702 | |||
| 677 | #if defined(CONFIG_TCC_BCHECK) | 703 | #if defined(CONFIG_TCC_BCHECK) |
| 678 | 704 | ||
| 679 | static void gen_bounds_call(int v) | 705 | static void gen_bounds_call(int v) |
| @@ -696,12 +722,13 @@ static void gen_bounds_prolog(void) · 16 unmodified lines | |||
| 696 | o(0xd503201f); /* nop -> call __bound_local_new */ | 722 | o(0xd503201f); /* nop -> call __bound_local_new */ |
| 697 | } | 723 | } |
| 698 | 724 | ||
| 699 | static void gen_bounds_epilog(void) | 725 | static void gen_bounds_epilog(Sym *func_sym) |
| 700 | { | 726 | { |
| 701 | addr_t saved_ind; | 727 | addr_t saved_ind; |
| 702 | addr_t *bounds_ptr; | 728 | addr_t *bounds_ptr; |
| 703 | Sym *sym_data; | 729 | Sym *sym_data; |
| 704 | int offset_modified = func_bound_offset != lbounds_section->data_offset; | 730 | int offset_modified = func_bound_offset != lbounds_section->data_offset; |
| 731 | CType *func_type = &func_sym->type.ref->type; | ||
| 705 | 732 | ||
| 706 | if (!offset_modified && !func_bound_add_epilog) | 733 | if (!offset_modified && !func_bound_add_epilog) |
| 707 | return; | 734 | return; |
| @@ -726,15 +753,15 @@ static void gen_bounds_epilog(void) · 18 unmodified lines | |||
| 726 | } | 753 | } |
| 727 | 754 | ||
| 728 | /* generate bound check local freeing */ | 755 | /* generate bound check local freeing */ |
| 729 | o(0xa9bf07e0); /* stp x0, x1, [sp, #-16]! */ | 756 | if (func_type->t != VT_VOID) |
| 730 | o(0x3c9f0fe0); /* str q0, [sp, #-16]! */ | 757 | save_return_reg(func_type); |
| 731 | greloca(cur_text_section, sym_data, ind, R_AARCH64_ADR_GOT_PAGE, 0); | 758 | greloca(cur_text_section, sym_data, ind, R_AARCH64_ADR_GOT_PAGE, 0); |
| 732 | o(0x90000000 | 0); // adrp x0, #sym_data | 759 | o(0x90000000 | 0); // adrp x0, #sym_data |
| 733 | greloca(cur_text_section, sym_data, ind, R_AARCH64_LD64_GOT_LO12_NC, 0); | 760 | greloca(cur_text_section, sym_data, ind, R_AARCH64_LD64_GOT_LO12_NC, 0); |
| 734 | o(0xf9400000 | 0 | (0 << 5)); // ld x0,[x0, #sym_data] | 761 | o(0xf9400000 | 0 | (0 << 5)); // ld x0,[x0, #sym_data] |
| 735 | gen_bounds_call(TOK___bound_local_delete); | 762 | gen_bounds_call(TOK___bound_local_delete); |
| 736 | o(0x3cc107e0); /* ldr q0, [sp], #16 */ | 763 | if (func_type->t != VT_VOID) |
| 737 | o(0xa8c107e0); /* ldp x0, x1, [sp], #16 */ | 764 | restore_return_reg(func_type); |
| 738 | } | 765 | } |
| 739 | #endif | 766 | #endif |
| 740 | 767 | ||
| @@ -1459,12 +1486,13 @@ ST_FUNC void gfunc_return(CType *func_type) · 718 unmodified lines | |||
| 1459 | vtop--; | 1486 | vtop--; |
| 1460 | } | 1487 | } |
| 1461 | 1488 | ||
| 1462 | ST_FUNC void gfunc_epilog(void) | 1489 | ST_FUNC void gfunc_epilog(Sym *func_sym) |
| 1463 | { | 1490 | { |
| 1464 | #ifdef CONFIG_TCC_BCHECK | 1491 | #ifdef CONFIG_TCC_BCHECK |
| 1465 | if (tcc_state->do_bounds_check) | 1492 | if (tcc_state->do_bounds_check) |
| 1466 | gen_bounds_epilog(); | 1493 | gen_bounds_epilog(func_sym); |
| 1467 | #endif | 1494 | #endif |
| 1495 | func_sym = NULL; | ||
| 1468 | 1496 | ||
| 1469 | if (loc) { | 1497 | if (loc) { |
| 1470 | // Insert instructions to subtract size of stack frame from SP. | 1498 | // Insert instructions to subtract size of stack frame from SP. |
| @@ -2019,9 +2019,22 @@ void gfunc_prolog(Sym *func_sym) · 2018 unmodified lines | |||
| 2019 | C67_PUSH(C67_B3); | 2019 | C67_PUSH(C67_B3); |
| 2020 | } | 2020 | } |
| 2021 | 2021 | ||
| 2022 | ST_FUNC void save_return_reg(CType *func_type) | ||
| 2023 | { | ||
| 2024 | func_type = NULL; | ||
| 2025 | // TODO | ||
| 2026 | } | ||
| 2027 | |||
| 2028 | ST_FUNC void restore_return_reg(CType *func_type) | ||
| 2029 | { | ||
| 2030 | func_type = NULL; | ||
| 2031 | // TODO | ||
| 2032 | } | ||
| 2033 | |||
| 2022 | /* generate function epilog */ | 2034 | /* generate function epilog */ |
| 2023 | void gfunc_epilog(void) | 2035 | void gfunc_epilog(Sym *func_sym) |
| 2024 | { | 2036 | { |
| 2037 | func_sym = NULL; | ||
| 2025 | { | 2038 | { |
| 2026 | int local = (-loc + 7) & -8; // stack must stay aligned to 8 bytes for LDDW instr | 2039 | int local = (-loc + 7) & -8; // stack must stay aligned to 8 bytes for LDDW instr |
| 2027 | C67_POP(C67_B3); | 2040 | C67_POP(C67_B3); |
| @@ -104,7 +104,7 @@ static addr_t func_bound_offset; · 103 unmodified lines | |||
| 104 | static unsigned long func_bound_ind; | 104 | static unsigned long func_bound_ind; |
| 105 | ST_DATA int func_bound_add_epilog; | 105 | ST_DATA int func_bound_add_epilog; |
| 106 | static void gen_bounds_prolog(void); | 106 | static void gen_bounds_prolog(void); |
| 107 | static void gen_bounds_epilog(void); | 107 | static void gen_bounds_epilog(Sym *func_sym); |
| 108 | #endif | 108 | #endif |
| 109 | 109 | ||
| 110 | /* XXX: make it faster ? */ | 110 | /* XXX: make it faster ? */ |
| @@ -595,14 +595,15 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) · 484 unmodified lines | |||
| 595 | } | 595 | } |
| 596 | 596 | ||
| 597 | /* generate function epilog */ | 597 | /* generate function epilog */ |
| 598 | ST_FUNC void gfunc_epilog(void) | 598 | ST_FUNC void gfunc_epilog(Sym *func_sym) |
| 599 | { | 599 | { |
| 600 | addr_t v, saved_ind; | 600 | addr_t v, saved_ind; |
| 601 | 601 | ||
| 602 | #ifdef CONFIG_TCC_BCHECK | 602 | #ifdef CONFIG_TCC_BCHECK |
| 603 | if (tcc_state->do_bounds_check) | 603 | if (tcc_state->do_bounds_check) |
| 604 | gen_bounds_epilog(); | 604 | gen_bounds_epilog(func_sym); |
| 605 | #endif | 605 | #endif |
| 606 | func_sym = NULL; | ||
| 606 | 607 | ||
| 607 | /* align local size to word & save local variables */ | 608 | /* align local size to word & save local variables */ |
| 608 | v = (-loc + 3) & -4; | 609 | v = (-loc + 3) & -4; |
| @@ -1040,6 +1041,22 @@ ST_FUNC void ggoto(void) · 431 unmodified lines | |||
| 1040 | vtop--; | 1041 | vtop--; |
| 1041 | } | 1042 | } |
| 1042 | 1043 | ||
| 1044 | ST_FUNC void save_return_reg(CType *func_type) | ||
| 1045 | { | ||
| 1046 | int ireg = !is_float(func_type->t & VT_BTYPE); | ||
| 1047 | |||
| 1048 | if (ireg) | ||
| 1049 | o(0x5250); /* push %rax; %push %rdx */ | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | ST_FUNC void restore_return_reg(CType *func_type) | ||
| 1053 | { | ||
| 1054 | int ireg = !is_float(func_type->t & VT_BTYPE); | ||
| 1055 | |||
| 1056 | if (ireg) | ||
| 1057 | o(0x585a); /* pop %rdx; pop %rax */ | ||
| 1058 | } | ||
| 1059 | |||
| 1043 | /* bound check support functions */ | 1060 | /* bound check support functions */ |
| 1044 | #ifdef CONFIG_TCC_BCHECK | 1061 | #ifdef CONFIG_TCC_BCHECK |
| 1045 | 1062 | ||
| @@ -1053,12 +1070,13 @@ static void gen_bounds_prolog(void) · 7 unmodified lines | |||
| 1053 | oad(0xb8, 0); /* call to function */ | 1070 | oad(0xb8, 0); /* call to function */ |
| 1054 | } | 1071 | } |
| 1055 | 1072 | ||
| 1056 | static void gen_bounds_epilog(void) | 1073 | static void gen_bounds_epilog(Sym *func_sym) |
| 1057 | { | 1074 | { |
| 1058 | addr_t saved_ind; | 1075 | addr_t saved_ind; |
| 1059 | addr_t *bounds_ptr; | 1076 | addr_t *bounds_ptr; |
| 1060 | Sym *sym_data; | 1077 | Sym *sym_data; |
| 1061 | int offset_modified = func_bound_offset != lbounds_section->data_offset; | 1078 | int offset_modified = func_bound_offset != lbounds_section->data_offset; |
| 1079 | CType *func_type = &func_sym->type.ref->type; | ||
| 1062 | 1080 | ||
| 1063 | if (!offset_modified && !func_bound_add_epilog) | 1081 | if (!offset_modified && !func_bound_add_epilog) |
| 1064 | return; | 1082 | return; |
| @@ -1081,11 +1099,13 @@ static void gen_bounds_epilog(void) · 16 unmodified lines | |||
| 1081 | } | 1099 | } |
| 1082 | 1100 | ||
| 1083 | /* generate bound check local freeing */ | 1101 | /* generate bound check local freeing */ |
| 1084 | o(0x5250); /* save returned value, if any */ | 1102 | if (func_type->t != VT_VOID) |
| 1103 | save_return_reg(func_type); | ||
| 1085 | greloc(cur_text_section, sym_data, ind + 1, R_386_32); | 1104 | greloc(cur_text_section, sym_data, ind + 1, R_386_32); |
| 1086 | oad(0xb8, 0); /* mov %eax, xxx */ | 1105 | oad(0xb8, 0); /* mov %eax, xxx */ |
| 1087 | gen_static_call(TOK___bound_local_delete); | 1106 | gen_static_call(TOK___bound_local_delete); |
| 1088 | o(0x585a); /* restore returned value, if any */ | 1107 | if (func_type->t != VT_VOID) |
| 1108 | restore_return_reg(func_type); | ||
| 1089 | } | 1109 | } |
| 1090 | #endif | 1110 | #endif |
| 1091 | 1111 | ||
| @@ -457,9 +457,20 @@ void gfunc_prolog(int t) · 456 unmodified lines | |||
| 457 | } | 457 | } |
| 458 | } | 458 | } |
| 459 | 459 | ||
| 460 | void save_return_reg(CType *func_type) | ||
| 461 | { | ||
| 462 | func_type = NULL; | ||
| 463 | } | ||
| 464 | |||
| 465 | void restore_return_reg(CType *func_type) | ||
| 466 | { | ||
| 467 | func_type = NULL; | ||
| 468 | } | ||
| 469 | |||
| 460 | /* generate function epilog */ | 470 | /* generate function epilog */ |
| 461 | void gfunc_epilog(void) | 471 | void gfunc_epilog(Sym *func_sym) |
| 462 | { | 472 | { |
| 473 | func_sym = NULL; | ||
| 463 | out_op(IL_OP_RET); | 474 | out_op(IL_OP_RET); |
| 464 | fprintf(il_outfile, "}\n\n"); | 475 | fprintf(il_outfile, "}\n\n"); |
| 465 | } | 476 | } |
| @@ -436,6 +436,46 @@ static void gcall_or_jmp(int docall) · 435 unmodified lines | |||
| 436 | } | 436 | } |
| 437 | } | 437 | } |
| 438 | 438 | ||
| 439 | ST_FUNC void save_return_reg(CType *func_type) | ||
| 440 | { | ||
| 441 | int freg = is_float(func_type->t & VT_BTYPE) && | ||
| 442 | (func_type->t & VT_BTYPE) != VT_LDOUBLE; | ||
| 443 | int ireg = !freg; | ||
| 444 | |||
| 445 | if ((func_type->t & VT_BTYPE) == VT_STRUCT) | ||
| 446 | ireg = freg = 1; | ||
| 447 | if (ireg && freg) { | ||
| 448 | o(0xe02a1101); /* addi sp,sp,-32 sd a0,0(sp) */ | ||
| 449 | o(0xa82ae42e); /* sd a1,8(sp) fsd fa0,16(sp) */ | ||
| 450 | } | ||
| 451 | else if (ireg) { | ||
| 452 | o(0xe02a1141); /* addi sp,sp,-16 sd a0,0(sp) */ | ||
| 453 | o(0x0001e42e); /* sd a1,8(sp) nop */ | ||
| 454 | } | ||
| 455 | else if (freg) | ||
| 456 | o(0xa02a1141); /* addi sp,sp,-16 fsd fa0,0(sp) */ | ||
| 457 | } | ||
| 458 | |||
| 459 | ST_FUNC void restore_return_reg(CType *func_type) | ||
| 460 | { | ||
| 461 | int freg = is_float(func_type->t & VT_BTYPE) && | ||
| 462 | (func_type->t & VT_BTYPE) != VT_LDOUBLE; | ||
| 463 | int ireg = !freg; | ||
| 464 | |||
| 465 | if ((func_type->t & VT_BTYPE) == VT_STRUCT) | ||
| 466 | ireg = freg = 1; | ||
| 467 | if (ireg && freg) { | ||
| 468 | o(0x65a26502); /* ld a0,0(sp) ld a1,8(sp) */ | ||
| 469 | o(0x61052542); /* fld fa0,16(sp) addi sp,sp,32 */ | ||
| 470 | } | ||
| 471 | else if (ireg) { | ||
| 472 | o(0x65a26502); /* ld a0,0(sp) ld a1,8(sp) */ | ||
| 473 | o(0x00010141); /* addi sp,sp,16 nop */ | ||
| 474 | } | ||
| 475 | else if (freg) | ||
| 476 | o(0x01412502); /* fld fa0,0(sp) addi sp,sp,16 */ | ||
| 477 | } | ||
| 478 | |||
| 439 | #if defined(CONFIG_TCC_BCHECK) | 479 | #if defined(CONFIG_TCC_BCHECK) |
| 440 | 480 | ||
| 441 | static void gen_bounds_call(int v) | 481 | static void gen_bounds_call(int v) |
| @@ -459,14 +499,14 @@ static void gen_bounds_prolog(void) · 17 unmodified lines | |||
| 459 | o(0x00000013); | 499 | o(0x00000013); |
| 460 | } | 500 | } |
| 461 | 501 | ||
| 462 | static void gen_bounds_epilog(void) | 502 | static void gen_bounds_epilog(Sym *func_sym) |
| 463 | { | 503 | { |
| 464 | addr_t saved_ind; | 504 | addr_t saved_ind; |
| 465 | addr_t *bounds_ptr; | 505 | addr_t *bounds_ptr; |
| 466 | Sym *sym_data; | 506 | Sym *sym_data; |
| 467 | Sym label = {0}; | 507 | Sym label = {0}; |
| 468 | |||
| 469 | int offset_modified = func_bound_offset != lbounds_section->data_offset; | 508 | int offset_modified = func_bound_offset != lbounds_section->data_offset; |
| 509 | CType *func_type = &func_sym->type.ref->type; | ||
| 470 | 510 | ||
| 471 | if (!offset_modified && !func_bound_add_epilog) | 511 | if (!offset_modified && !func_bound_add_epilog) |
| 472 | return; | 512 | return; |
| @@ -494,16 +534,16 @@ static void gen_bounds_epilog(void) · 21 unmodified lines | |||
| 494 | } | 534 | } |
| 495 | 535 | ||
| 496 | /* generate bound check local freeing */ | 536 | /* generate bound check local freeing */ |
| 497 | o(0xe02a1101); /* addi sp,sp,-32 sd a0,0(sp) */ | 537 | if (func_type->t != VT_VOID) |
| 498 | o(0xa82ae42e); /* sd a1,8(sp) fsd fa0,16(sp) */ | 538 | save_return_reg(func_type); |
| 499 | put_extern_sym(&label, cur_text_section, ind, 0); | 539 | put_extern_sym(&label, cur_text_section, ind, 0); |
| 500 | greloca(cur_text_section, sym_data, ind, R_RISCV_GOT_HI20, 0); | 540 | greloca(cur_text_section, sym_data, ind, R_RISCV_GOT_HI20, 0); |
| 501 | o(0x17 | (10 << 7)); // auipc a0, 0 %pcrel_hi(sym)+addend | 541 | o(0x17 | (10 << 7)); // auipc a0, 0 %pcrel_hi(sym)+addend |
| 502 | greloca(cur_text_section, &label, ind, R_RISCV_PCREL_LO12_I, 0); | 542 | greloca(cur_text_section, &label, ind, R_RISCV_PCREL_LO12_I, 0); |
| 503 | EI(0x03, 3, 10, 10, 0); // ld a0, 0(a0) | 543 | EI(0x03, 3, 10, 10, 0); // ld a0, 0(a0) |
| 504 | gen_bounds_call(TOK___bound_local_delete); | 544 | gen_bounds_call(TOK___bound_local_delete); |
| 505 | o(0x65a26502); /* ld a0,0(sp) ld a1,8(sp) */ | 545 | if (func_type->t != VT_VOID) |
| 506 | o(0x61052542); /* fld fa0,16(sp) addi sp,sp,32 */ | 546 | restore_return_reg(func_type); |
| 507 | } | 547 | } |
| 508 | #endif | 548 | #endif |
| 509 | 549 | ||
| @@ -893,14 +933,15 @@ ST_FUNC void arch_transfer_ret_regs(int aftercall) · 383 unmodified lines | |||
| 893 | vtop--; | 933 | vtop--; |
| 894 | } | 934 | } |
| 895 | 935 | ||
| 896 | ST_FUNC void gfunc_epilog(void) | 936 | ST_FUNC void gfunc_epilog(Sym *func_sym) |
| 897 | { | 937 | { |
| 898 | int v, saved_ind, d, large_ofs_ind; | 938 | int v, saved_ind, d, large_ofs_ind; |
| 899 | 939 | ||
| 900 | #ifdef CONFIG_TCC_BCHECK | 940 | #ifdef CONFIG_TCC_BCHECK |
| 901 | if (tcc_state->do_bounds_check) | 941 | if (tcc_state->do_bounds_check) |
| 902 | gen_bounds_epilog(); | 942 | gen_bounds_epilog(func_sym); |
| 903 | #endif | 943 | #endif |
| 944 | func_sym = NULL; | ||
| 904 | 945 | ||
| 905 | loc = (loc - num_va_regs * 8); | 946 | loc = (loc - num_va_regs * 8); |
| 906 | d = v = (-loc + 15) & -16; | 947 | d = v = (-loc + 15) & -16; |
| @@ -1607,7 +1607,9 @@ ST_FUNC void store(int r, SValue *v); · 1606 unmodified lines | |||
| 1607 | ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize); | 1607 | ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize); |
| 1608 | ST_FUNC void gfunc_call(int nb_args); | 1608 | ST_FUNC void gfunc_call(int nb_args); |
| 1609 | ST_FUNC void gfunc_prolog(Sym *func_sym); | 1609 | ST_FUNC void gfunc_prolog(Sym *func_sym); |
| 1610 | ST_FUNC void gfunc_epilog(void); | 1610 | ST_FUNC void gfunc_epilog(Sym *func_sym); |
| 1611 | ST_FUNC void save_return_reg(CType *func_type); | ||
| 1612 | ST_FUNC void restore_return_reg(CType *func_type); | ||
| 1611 | ST_FUNC void gen_fill_nops(int); | 1613 | ST_FUNC void gen_fill_nops(int); |
| 1612 | ST_FUNC int gjmp(int t); | 1614 | ST_FUNC int gjmp(int t); |
| 1613 | ST_FUNC void gjmp_addr(int a); | 1615 | ST_FUNC void gjmp_addr(int a); |
| @@ -6839,10 +6839,14 @@ static void end_switch(void) · 6838 unmodified lines | |||
| 6839 | /* ------------------------------------------------------------------------- */ | 6839 | /* ------------------------------------------------------------------------- */ |
| 6840 | /* __attribute__((cleanup(fn))) */ | 6840 | /* __attribute__((cleanup(fn))) */ |
| 6841 | 6841 | ||
| 6842 | static void try_call_scope_cleanup(Sym *stop) | 6842 | static void try_call_scope_cleanup(Sym *stop, CType *func_type) |
| 6843 | { | 6843 | { |
| 6844 | Sym *cls = cur_scope->cl.s; | 6844 | Sym *cls = cur_scope->cl.s; |
| 6845 | 6845 | ||
| 6846 | if (cls == stop) | ||
| 6847 | func_type = NULL; | ||
| 6848 | if (func_type && func_type->t != VT_VOID) | ||
| 6849 | save_return_reg(func_type); | ||
| 6846 | for (; cls != stop; cls = cls->next) { | 6850 | for (; cls != stop; cls = cls->next) { |
| 6847 | Sym *fs = cls->cleanup_func; | 6851 | Sym *fs = cls->cleanup_func; |
| 6848 | Sym *vs = cls->prev_tok; | 6852 | Sym *vs = cls->prev_tok; |
| @@ -6854,6 +6858,8 @@ static void try_call_scope_cleanup(Sym *stop) · 5 unmodified lines | |||
| 6854 | gaddrof(); | 6858 | gaddrof(); |
| 6855 | gfunc_call(1); | 6859 | gfunc_call(1); |
| 6856 | } | 6860 | } |
| 6861 | if (func_type && func_type->t != VT_VOID) | ||
| 6862 | restore_return_reg(func_type); | ||
| 6857 | } | 6863 | } |
| 6858 | 6864 | ||
| 6859 | static void try_call_cleanup_goto(Sym *cleanupstate) | 6865 | static void try_call_cleanup_goto(Sym *cleanupstate) |
| @@ -6873,7 +6879,7 @@ static void try_call_cleanup_goto(Sym *cleanupstate) · 13 unmodified lines | |||
| 6873 | for (; cc != oc; cc = cc->next, oc = oc->next, --ccd) | 6879 | for (; cc != oc; cc = cc->next, oc = oc->next, --ccd) |
| 6874 | ; | 6880 | ; |
| 6875 | 6881 | ||
| 6876 | try_call_scope_cleanup(cc); | 6882 | try_call_scope_cleanup(cc, NULL); |
| 6877 | } | 6883 | } |
| 6878 | 6884 | ||
| 6879 | /* call 'func' for each __attribute__((cleanup(func))) */ | 6885 | /* call 'func' for each __attribute__((cleanup(func))) */ |
| @@ -6887,7 +6893,7 @@ static void block_cleanup(struct scope *o) · 7 unmodified lines | |||
| 6887 | if (!jmp) | 6893 | if (!jmp) |
| 6888 | jmp = gjmp(0); | 6894 | jmp = gjmp(0); |
| 6889 | gsym(pcl->jnext); | 6895 | gsym(pcl->jnext); |
| 6890 | try_call_scope_cleanup(o->cl.s); | 6896 | try_call_scope_cleanup(o->cl.s, NULL); |
| 6891 | pcl->jnext = gjmp(0); | 6897 | pcl->jnext = gjmp(0); |
| 6892 | if (!o->cl.n) | 6898 | if (!o->cl.n) |
| 6893 | goto remove_pending; | 6899 | goto remove_pending; |
| @@ -6900,7 +6906,7 @@ static void block_cleanup(struct scope *o) · 6 unmodified lines | |||
| 6900 | } | 6906 | } |
| 6901 | } | 6907 | } |
| 6902 | gsym(jmp); | 6908 | gsym(jmp); |
| 6903 | try_call_scope_cleanup(o->cl.s); | 6909 | try_call_scope_cleanup(o->cl.s, NULL); |
| 6904 | } | 6910 | } |
| 6905 | 6911 | ||
| 6906 | /* ------------------------------------------------------------------------- */ | 6912 | /* ------------------------------------------------------------------------- */ |
| @@ -6964,11 +6970,11 @@ static void prev_scope(struct scope *o, int is_expr) · 57 unmodified lines | |||
| 6964 | } | 6970 | } |
| 6965 | 6971 | ||
| 6966 | /* leave a scope via break/continue(/goto) */ | 6972 | /* leave a scope via break/continue(/goto) */ |
| 6967 | static void leave_scope(struct scope *o) | 6973 | static void leave_scope(struct scope *o, CType *func_type) |
| 6968 | { | 6974 | { |
| 6969 | if (!o) | 6975 | if (!o) |
| 6970 | return; | 6976 | return; |
| 6971 | try_call_scope_cleanup(o->cl.s); | 6977 | try_call_scope_cleanup(o->cl.s, func_type); |
| 6972 | vla_leave(o); | 6978 | vla_leave(o); |
| 6973 | } | 6979 | } |
| 6974 | 6980 | ||
| @@ -7110,9 +7116,9 @@ again: · 135 unmodified lines | |||
| 7110 | tcc_warning("'return' with no value"); | 7116 | tcc_warning("'return' with no value"); |
| 7111 | b = 0; | 7117 | b = 0; |
| 7112 | } | 7118 | } |
| 7113 | leave_scope(root_scope); | ||
| 7114 | if (b) | 7119 | if (b) |
| 7115 | gfunc_return(&func_vt); | 7120 | gfunc_return(&func_vt); |
| 7121 | leave_scope(root_scope, &func_vt); | ||
| 7116 | skip(';'); | 7122 | skip(';'); |
| 7117 | /* jump unless last stmt in top-level block */ | 7123 | /* jump unless last stmt in top-level block */ |
| 7118 | if (tok != '}' || local_scope != 1) | 7124 | if (tok != '}' || local_scope != 1) |
| @@ -7126,9 +7132,9 @@ again: · 7 unmodified lines | |||
| 7126 | if (!cur_scope->bsym) | 7132 | if (!cur_scope->bsym) |
| 7127 | tcc_error("cannot break"); | 7133 | tcc_error("cannot break"); |
| 7128 | if (cur_switch && cur_scope->bsym == cur_switch->bsym) | 7134 | if (cur_switch && cur_scope->bsym == cur_switch->bsym) |
| 7129 | leave_scope(cur_switch->scope); | 7135 | leave_scope(cur_switch->scope, NULL); |
| 7130 | else | 7136 | else |
| 7131 | leave_scope(loop_scope); | 7137 | leave_scope(loop_scope, NULL); |
| 7132 | *cur_scope->bsym = gjmp(*cur_scope->bsym); | 7138 | *cur_scope->bsym = gjmp(*cur_scope->bsym); |
| 7133 | skip(';'); | 7139 | skip(';'); |
| 7134 | 7140 | ||
| @@ -7136,7 +7142,7 @@ again: · 1 unmodified line | |||
| 7136 | /* compute jump */ | 7142 | /* compute jump */ |
| 7137 | if (!cur_scope->csym) | 7143 | if (!cur_scope->csym) |
| 7138 | tcc_error("cannot continue"); | 7144 | tcc_error("cannot continue"); |
| 7139 | leave_scope(loop_scope); | 7145 | leave_scope(loop_scope, NULL); |
| 7140 | *cur_scope->csym = gjmp(*cur_scope->csym); | 7146 | *cur_scope->csym = gjmp(*cur_scope->csym); |
| 7141 | skip(';'); | 7147 | skip(';'); |
| 7142 | 7148 | ||
| @@ -8400,7 +8406,7 @@ static void gen_function(Sym *sym) · 1257 unmodified lines | |||
| 8400 | /* reset local stack */ | 8406 | /* reset local stack */ |
| 8401 | pop_local_syms(NULL, 0); | 8407 | pop_local_syms(NULL, 0); |
| 8402 | tcc_debug_prolog_epilog(tcc_state, 1); | 8408 | tcc_debug_prolog_epilog(tcc_state, 1); |
| 8403 | gfunc_epilog(); | 8409 | gfunc_epilog(sym); |
| 8404 | 8410 | ||
| 8405 | /* end of function */ | 8411 | /* end of function */ |
| 8406 | tcc_debug_funcend(tcc_state, ind - func_ind); | 8412 | tcc_debug_funcend(tcc_state, ind - func_ind); |
| @@ -495,7 +495,9 @@ static void bt_link(TCCState *s1) · 494 unmodified lines | |||
| 495 | { | 495 | { |
| 496 | #ifdef CONFIG_TCC_BACKTRACE | 496 | #ifdef CONFIG_TCC_BACKTRACE |
| 497 | rt_context *rc; | 497 | rt_context *rc; |
| 498 | #ifdef CONFIG_TCC_BCHECK | ||
| 498 | void *p; | 499 | void *p; |
| 500 | #endif | ||
| 499 | 501 | ||
| 500 | if (!s1->do_backtrace) | 502 | if (!s1->do_backtrace) |
| 501 | return; | 503 | return; |
| @@ -1,9 +1,15 @@ | |||
| 1 | extern int printf(const char*, ...); | 1 | extern int printf(const char*, ...); |
| 2 | static int glob_i = 0; | 2 | static int glob_i = 0; |
| 3 | 3 | ||
| 4 | typedef struct { int a; int b; int c; int d; int e; int f; int g; int h; } tstl; | ||
| 5 | typedef struct { int a; int b; int c; int d; } tsti; | ||
| 6 | typedef struct { double a; double b; } tstd; | ||
| 7 | typedef struct { long double a; } tstld; | ||
| 8 | |||
| 4 | void incr_glob_i(int *i) | 9 | void incr_glob_i(int *i) |
| 5 | { | 10 | { |
| 6 | glob_i += *i; | 11 | glob_i += *i; |
| 12 | *i = -1; | ||
| 7 | } | 13 | } |
| 8 | 14 | ||
| 9 | #define INCR_GI { \ | 15 | #define INCR_GI { \ |
| @@ -71,17 +77,20 @@ void check(int *j) · 61 unmodified lines | |||
| 71 | goto out; | 77 | goto out; |
| 72 | } | 78 | } |
| 73 | } | 79 | } |
| 80 | *j = -1; | ||
| 74 | return; | 81 | return; |
| 75 | } | 82 | } |
| 76 | 83 | ||
| 77 | void check_oh_i(char *oh_i) | 84 | void check_oh_i(char *oh_i) |
| 78 | { | 85 | { |
| 79 | printf("c: %c\n", *oh_i); | 86 | printf("c: %c\n", *oh_i); |
| 87 | *oh_i = '0'; | ||
| 80 | } | 88 | } |
| 81 | 89 | ||
| 82 | void goto_hell(double *f) | 90 | void goto_hell(double *f) |
| 83 | { | 91 | { |
| 84 | printf("oo: %f\n", *f); | 92 | printf("oo: %f\n", *f); |
| 93 | *f = -1.0; | ||
| 85 | } | 94 | } |
| 86 | 95 | ||
| 87 | char *test() | 96 | char *test() |
| @@ -152,6 +161,7 @@ int test3(void) { · 64 unmodified lines | |||
| 152 | void cl(int *ip) | 161 | void cl(int *ip) |
| 153 | { | 162 | { |
| 154 | printf("%d\n", *ip); | 163 | printf("%d\n", *ip); |
| 164 | *ip = -1; | ||
| 155 | } | 165 | } |
| 156 | 166 | ||
| 157 | void loop_cleanups(void) | 167 | void loop_cleanups(void) |
| @@ -191,11 +201,72 @@ void loop_cleanups(void) · 33 unmodified lines | |||
| 191 | printf("after break\n"); | 201 | printf("after break\n"); |
| 192 | } | 202 | } |
| 193 | 203 | ||
| 204 | void my_cleanup1(int *p) { | ||
| 205 | printf("%d\n", *p); | ||
| 206 | *p = 0x90; | ||
| 207 | } | ||
| 208 | |||
| 209 | int test_cleanup1(void) { | ||
| 210 | int __attribute__((cleanup(my_cleanup1))) n = 42; | ||
| 211 | return n; | ||
| 212 | } | ||
| 213 | |||
| 214 | void my_cleanup2(tstl *p) { | ||
| 215 | printf("%d %d %d %d %d %d %d %d\n", p->a, p->b, p->c, p->d, | ||
| 216 | p->e, p->f, p->g, p->h); | ||
| 217 | p->a = 0x90; p->b = 0x91; p->c = 0x92; p->d = 0x93; | ||
| 218 | p->e = 0x94; p->f = 0x95; p->g = 0x96; p->h = 0x97; | ||
| 219 | } | ||
| 220 | |||
| 221 | tstl test_cleanup2(void) { | ||
| 222 | tstl __attribute__((cleanup(my_cleanup2))) n; | ||
| 223 | n.a = 42; n.b = 43; n.c = 44; n.d = 45; | ||
| 224 | n.e = 46; n.f = 47; n.g = 48; n.h = 49; | ||
| 225 | return n; | ||
| 226 | } | ||
| 227 | |||
| 228 | void my_cleanup3(tsti *p) { | ||
| 229 | printf("%d %d %d %d\n", p->a, p->b, p->c, p->d); | ||
| 230 | p->a = 0x90; p->b = 0x91; p->c = 0x92; p->d = 0x93; | ||
| 231 | } | ||
| 232 | |||
| 233 | tsti test_cleanup3(void) { | ||
| 234 | tsti __attribute__((cleanup(my_cleanup3))) n; | ||
| 235 | n.a = 42; n.b = 43; n.c = 44; n.d = 45; | ||
| 236 | return n; | ||
| 237 | } | ||
| 238 | |||
| 239 | void my_cleanup4(tstd *p) { | ||
| 240 | printf("%g %g\n", p->a, p->b); | ||
| 241 | p->a = 90.0; p->b = 91.0; | ||
| 242 | } | ||
| 243 | |||
| 244 | tstd test_cleanup4(void) { | ||
| 245 | tstd __attribute__((cleanup(my_cleanup4))) n; | ||
| 246 | n.a = 42.0; n.b = 43.0; | ||
| 247 | return n; | ||
| 248 | } | ||
| 249 | |||
| 250 | void my_cleanup5(tstld *p) { | ||
| 251 | printf("%Lf\n", p->a); | ||
| 252 | p->a = 90.0; | ||
| 253 | } | ||
| 254 | |||
| 255 | tstld test_cleanup5(void) { | ||
| 256 | tstld __attribute__((cleanup(my_cleanup5))) n; | ||
| 257 | n.a = 42.0; | ||
| 258 | return n; | ||
| 259 | } | ||
| 260 | |||
| 194 | int main() | 261 | int main() |
| 195 | { | 262 | { |
| 196 | int i __attribute__ ((__cleanup__(check))) = 0, not_i; | 263 | int i __attribute__ ((__cleanup__(check))) = 0, not_i; |
| 197 | int chk = 0; | 264 | int chk = 0; |
| 198 | (void)not_i; | 265 | (void)not_i; |
| 266 | tstl tl; | ||
| 267 | tsti ti; | ||
| 268 | tstd td; | ||
| 269 | tstld tld; | ||
| 199 | 270 | ||
| 200 | { | 271 | { |
| 201 | __attribute__ ((__cleanup__(check_oh_i))) char oh_i = 'o', o = 'a'; | 272 | __attribute__ ((__cleanup__(check_oh_i))) char oh_i = 'o', o = 'a'; |
| @@ -218,10 +289,21 @@ int main() · 16 unmodified lines | |||
| 218 | test2(); | 289 | test2(); |
| 219 | test3(); | 290 | test3(); |
| 220 | loop_cleanups(); | 291 | loop_cleanups(); |
| 292 | printf("%d\n", test_cleanup1()); | ||
| 293 | tl = test_cleanup2(); | ||
| 294 | printf("%d %d %d %d %d %d %d %d\n", tl.a, tl.b, tl.c, tl.d, | ||
| 295 | tl.e, tl.f, tl.g, tl.h); | ||
| 296 | ti = test_cleanup3(); | ||
| 297 | printf("%d %d %d %d\n", ti.a, ti.b, ti.c, ti.d); | ||
| 298 | td = test_cleanup4(); | ||
| 299 | printf("%g %g\n", td.a, td.b); | ||
| 300 | tld = test_cleanup5(); | ||
| 301 | printf("%Lf\n", tld.a); | ||
| 221 | return i; | 302 | return i; |
| 222 | } | 303 | } |
| 223 | 304 | ||
| 224 | void check2(char **hum) | 305 | void check2(char **hum) |
| 225 | { | 306 | { |
| 226 | printf("str: %s\n", *hum); | 307 | printf("str: %s\n", *hum); |
| 308 | *hum = "fail"; | ||
| 227 | } | 309 | } |
| @@ -48,6 +48,16 @@ str: three · 47 unmodified lines | |||
| 48 | 400 | 48 | 400 |
| 49 | after break | 49 | after break |
| 50 | 1000 | 50 | 1000 |
| 51 | 42 | ||
| 52 | 42 | ||
| 53 | 42 43 44 45 46 47 48 49 | ||
| 54 | 42 43 44 45 46 47 48 49 | ||
| 55 | 42 43 44 45 | ||
| 56 | 42 43 44 45 | ||
| 57 | 42 43 | ||
| 58 | 42 43 | ||
| 59 | 42.000000 | ||
| 60 | 42.000000 | ||
| 51 | ---- 0 | 61 | ---- 0 |
| 52 | ---- 1 | 62 | ---- 1 |
| 53 | str: plop | 63 | str: plop |
| @@ -31,6 +31,7 @@ ifeq ($(CONFIG_bcheck),no) · 30 unmodified lines | |||
| 31 | SKIP += 116_bound_setjmp2.test | 31 | SKIP += 116_bound_setjmp2.test |
| 32 | SKIP += 117_builtins.test | 32 | SKIP += 117_builtins.test |
| 33 | SKIP += 126_bound_global.test | 33 | SKIP += 126_bound_global.test |
| 34 | SKIP += 132_bound_test.test | ||
| 34 | endif | 35 | endif |
| 35 | ifeq ($(CONFIG_dll),no) | 36 | ifeq ($(CONFIG_dll),no) |
| 36 | SKIP += 113_btdll.test # no shared lib support yet | 37 | SKIP += 113_btdll.test # no shared lib support yet |
| @@ -655,6 +655,50 @@ static void gcall_or_jmp(int is_jmp) · 654 unmodified lines | |||
| 655 | } | 655 | } |
| 656 | } | 656 | } |
| 657 | 657 | ||
| 658 | ST_FUNC void save_return_reg(CType *func_type) | ||
| 659 | { | ||
| 660 | int freg = is_float(func_type->t & VT_BTYPE); | ||
| 661 | int ireg = !freg; | ||
| 662 | |||
| 663 | if ((func_type->t & VT_BTYPE) == VT_STRUCT) | ||
| 664 | ireg = freg = 1; | ||
| 665 | if (ireg) | ||
| 666 | o(0x5250); /* push %rax; %push %rdx */ | ||
| 667 | if (freg) { | ||
| 668 | if ((func_type->t & VT_BTYPE) == VT_LDOUBLE || | ||
| 669 | (func_type->t & VT_BTYPE) == VT_STRUCT) { | ||
| 670 | o(0x10ec8348); /* sub $16,%rsp */ | ||
| 671 | o(0x243cdb); /* fstpt (%rsp) */ | ||
| 672 | } | ||
| 673 | o(0x20ec8348); /* sub $32,%rsp */ | ||
| 674 | o(0x290f); /* movaps %xmm0,0x10(%rsp) */ | ||
| 675 | o(0x102444); | ||
| 676 | o(0x240c290f); /* movaps %xmm1,(%rsp) */ | ||
| 677 | } | ||
| 678 | } | ||
| 679 | |||
| 680 | ST_FUNC void restore_return_reg(CType *func_type) | ||
| 681 | { | ||
| 682 | int freg = is_float(func_type->t & VT_BTYPE); | ||
| 683 | int ireg = !freg; | ||
| 684 | |||
| 685 | if ((func_type->t & VT_BTYPE) == VT_STRUCT) | ||
| 686 | ireg = freg = 1; | ||
| 687 | if (freg) { | ||
| 688 | o(0x280f); /* movaps 0x10(%rsp),%xmm0 */ | ||
| 689 | o(0x102444); | ||
| 690 | o(0x240c280f); /* movaps (%rsp),%xmm1 */ | ||
| 691 | o(0x20c48348); /* add $32,%rsp */ | ||
| 692 | if ((func_type->t & VT_BTYPE) == VT_LDOUBLE || | ||
| 693 | (func_type->t & VT_BTYPE) == VT_STRUCT) { | ||
| 694 | o(0x242cdb); /* fldt (%rsp) */ | ||
| 695 | o(0x10c48348); /* add $16,%rsp */ | ||
| 696 | } | ||
| 697 | } | ||
| 698 | if (ireg) | ||
| 699 | o(0x585a); /* pop %rdx; pop %rax */ | ||
| 700 | } | ||
| 701 | |||
| 658 | #if defined(CONFIG_TCC_BCHECK) | 702 | #if defined(CONFIG_TCC_BCHECK) |
| 659 | 703 | ||
| 660 | static void gen_bounds_call(int v) | 704 | static void gen_bounds_call(int v) |
| @@ -681,12 +725,13 @@ static void gen_bounds_prolog(void) · 20 unmodified lines | |||
| 681 | oad(0xb8, 0); /* call to function */ | 725 | oad(0xb8, 0); /* call to function */ |
| 682 | } | 726 | } |
| 683 | 727 | ||
| 684 | static void gen_bounds_epilog(void) | 728 | static void gen_bounds_epilog(Sym *func_sym) |
| 685 | { | 729 | { |
| 686 | addr_t saved_ind; | 730 | addr_t saved_ind; |
| 687 | addr_t *bounds_ptr; | 731 | addr_t *bounds_ptr; |
| 688 | Sym *sym_data; | 732 | Sym *sym_data; |
| 689 | int offset_modified = func_bound_offset != lbounds_section->data_offset; | 733 | int offset_modified = func_bound_offset != lbounds_section->data_offset; |
| 734 | CType *func_type = &func_sym->type.ref->type; | ||
| 690 | 735 | ||
| 691 | if (!offset_modified && !func_bound_add_epilog) | 736 | if (!offset_modified && !func_bound_add_epilog) |
| 692 | return; | 737 | return; |
| @@ -709,20 +754,14 @@ static void gen_bounds_epilog(void) · 16 unmodified lines | |||
| 709 | } | 754 | } |
| 710 | 755 | ||
| 711 | /* generate bound check local freeing */ | 756 | /* generate bound check local freeing */ |
| 712 | o(0x5250); /* save returned value, if any */ | 757 | if (func_type->t != VT_VOID) |
| 713 | o(0x20ec8348); /* sub $32,%rsp */ | 758 | save_return_reg(func_type); |
| 714 | o(0x290f); /* movaps %xmm0,0x10(%rsp) */ | ||
| 715 | o(0x102444); | ||
| 716 | o(0x240c290f); /* movaps %xmm1,(%rsp) */ | ||
| 717 | greloca(cur_text_section, sym_data, ind + 3, R_X86_64_PC32, -4); | 759 | greloca(cur_text_section, sym_data, ind + 3, R_X86_64_PC32, -4); |
| 718 | o(0x0d8d48 + ((TREG_FASTCALL_1 == TREG_RDI) * 0x300000)); /* lea xxx(%rip), %rcx/rdi */ | 760 | o(0x0d8d48 + ((TREG_FASTCALL_1 == TREG_RDI) * 0x300000)); /* lea xxx(%rip), %rcx/rdi */ |
| 719 | gen_le32 (0); | 761 | gen_le32 (0); |
| 720 | gen_bounds_call(TOK___bound_local_delete); | 762 | gen_bounds_call(TOK___bound_local_delete); |
| 721 | o(0x280f); /* movaps 0x10(%rsp),%xmm0 */ | 763 | if (func_type->t != VT_VOID) |
| 722 | o(0x102444); | 764 | restore_return_reg(func_type); |
| 723 | o(0x240c280f); /* movaps (%rsp),%xmm1 */ | ||
| 724 | o(0x20c48348); /* add $32,%rsp */ | ||
| 725 | o(0x585a); /* restore returned value, if any */ | ||
| 726 | } | 765 | } |
| 727 | #endif | 766 | #endif |
| 728 | 767 | ||
| @@ -1005,7 +1044,7 @@ void gfunc_prolog(Sym *func_sym) · 276 unmodified lines | |||
| 1005 | } | 1044 | } |
| 1006 | 1045 | ||
| 1007 | /* generate function epilog */ | 1046 | /* generate function epilog */ |
| 1008 | void gfunc_epilog(void) | 1047 | void gfunc_epilog(Sym *func_sym) |
| 1009 | { | 1048 | { |
| 1010 | int v, start; | 1049 | int v, start; |
| 1011 | 1050 | ||
| @@ -1015,8 +1054,9 @@ void gfunc_epilog(void) · 3 unmodified lines | |||
| 1015 | 1054 | ||
| 1016 | #ifdef CONFIG_TCC_BCHECK | 1055 | #ifdef CONFIG_TCC_BCHECK |
| 1017 | if (tcc_state->do_bounds_check) | 1056 | if (tcc_state->do_bounds_check) |
| 1018 | gen_bounds_epilog(); | 1057 | gen_bounds_epilog(func_sym); |
| 1019 | #endif | 1058 | #endif |
| 1059 | func_sym = NULL; | ||
| 1020 | 1060 | ||
| 1021 | o(0xc9); /* leave */ | 1061 | o(0xc9); /* leave */ |
| 1022 | if (func_ret_sub == 0) { | 1062 | if (func_ret_sub == 0) { |
| @@ -1600,14 +1640,16 @@ void gfunc_prolog(Sym *func_sym) · 577 unmodified lines | |||
| 1600 | } | 1640 | } |
| 1601 | 1641 | ||
| 1602 | /* generate function epilog */ | 1642 | /* generate function epilog */ |
| 1603 | void gfunc_epilog(void) | 1643 | void gfunc_epilog(Sym *func_sym) |
| 1604 | { | 1644 | { |
| 1605 | int v, saved_ind; | 1645 | int v, saved_ind; |
| 1606 | 1646 | ||
| 1607 | #ifdef CONFIG_TCC_BCHECK | 1647 | #ifdef CONFIG_TCC_BCHECK |
| 1608 | if (tcc_state->do_bounds_check) | 1648 | if (tcc_state->do_bounds_check) |
| 1609 | gen_bounds_epilog(); | 1649 | gen_bounds_epilog(func_sym); |
| 1610 | #endif | 1650 | #endif |
| 1651 | func_sym = NULL; | ||
| 1652 | |||
| 1611 | o(0xc9); /* leave */ | 1653 | o(0xc9); /* leave */ |
| 1612 | if (func_ret_sub == 0) { | 1654 | if (func_ret_sub == 0) { |
| 1613 | o(0xc3); /* ret */ | 1655 | o(0xc3); /* ret */ |