History

Save registers around attribute cleanup

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.

herman ten brugge committed 1 year ago

Commit b6a16e31 parent 6ca228313 files · +344 −57Browse files

Unified · Split

13 files
  1. arm-gen.c +36 −7
  2. arm64-gen.c +35 −7
  3. c67-gen.c +14 −1
  4. i386-gen.c +26 −6
  5. il-gen.c +12 −1
  6. riscv64-gen.c +49 −8
  7. tcc.h +3 −1
  8. tccgen.c +17 −11
  9. tccrun.c +2 −0
  10. tests/tests2/101_cleanup.c +82 −0
  11. tests/tests2/101_cleanup.expect +10 −0
  12. tests/tests2/Makefile +1 −0
  13. x86_64-gen.c +57 −15
arm-gen.c+36−7
@@ -837,6 +837,32 @@ static void gcall_or_jmp(int is_jmp) · 836 unmodified lines
837 }837 }
838}838}
839 839
840ST_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
853ST_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
842static void gen_bounds_call(int v)868static 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
863static void gen_bounds_epilog(void)889static 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#endif932#endif
906 933
@@ -1508,15 +1535,17 @@ from_stack: · 601 unmodified lines
1508}1535}
1509 1536
1510/* generate function epilog */1537/* generate function epilog */
1511void gfunc_epilog(void)1538void 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_BCHECK1543#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#endif1546#endif
1547 func_sym = NULL;
1548
1520 /* Copy float return value to core register if base standard is used and1549 /* 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)
arm64-gen.c+35−7
@@ -674,6 +674,32 @@ static void arm64_gen_bl_or_b(int b) · 673 unmodified lines
674 }674 }
675}675}
676 676
677ST_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
690ST_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
679static void gen_bounds_call(int v)705static 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
699static void gen_bounds_epilog(void)725static 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_data759 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#endif766#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
1462ST_FUNC void gfunc_epilog(void)1489ST_FUNC void gfunc_epilog(Sym *func_sym)
1463{1490{
1464#ifdef CONFIG_TCC_BCHECK1491#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#endif1494#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.
c67-gen.c+14−1
@@ -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
2022ST_FUNC void save_return_reg(CType *func_type)
2023{
2024 func_type = NULL;
2025 // TODO
2026}
2027
2028ST_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 */
2023void gfunc_epilog(void)2035void 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 instr2039 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);
i386-gen.c+26−6
@@ -104,7 +104,7 @@ static addr_t func_bound_offset; · 103 unmodified lines
104static unsigned long func_bound_ind;104static unsigned long func_bound_ind;
105ST_DATA int func_bound_add_epilog;105ST_DATA int func_bound_add_epilog;
106static void gen_bounds_prolog(void);106static void gen_bounds_prolog(void);
107static void gen_bounds_epilog(void);107static void gen_bounds_epilog(Sym *func_sym);
108#endif108#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 */
598ST_FUNC void gfunc_epilog(void)598ST_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_BCHECK602#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#endif605#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
1044ST_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
1052ST_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_BCHECK1061#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
1056static void gen_bounds_epilog(void)1073static 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#endif1110#endif
1091 1111
il-gen.c+12−1
@@ -457,9 +457,20 @@ void gfunc_prolog(int t) · 456 unmodified lines
457 }457 }
458}458}
459 459
460void save_return_reg(CType *func_type)
461{
462 func_type = NULL;
463}
464
465void restore_return_reg(CType *func_type)
466{
467 func_type = NULL;
468}
469
460/* generate function epilog */470/* generate function epilog */
461void gfunc_epilog(void)471void 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}
riscv64-gen.c+49−8
@@ -436,6 +436,46 @@ static void gcall_or_jmp(int docall) · 435 unmodified lines
436 }436 }
437}437}
438 438
439ST_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
459ST_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
441static void gen_bounds_call(int v)481static 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
462static void gen_bounds_epilog(void)502static 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)+addend541 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#endif548#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
896ST_FUNC void gfunc_epilog(void)936ST_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_BCHECK940#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#endif943#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;
tcc.h+3−1
@@ -1607,7 +1607,9 @@ ST_FUNC void store(int r, SValue *v); · 1606 unmodified lines
1607ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize);1607ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize);
1608ST_FUNC void gfunc_call(int nb_args);1608ST_FUNC void gfunc_call(int nb_args);
1609ST_FUNC void gfunc_prolog(Sym *func_sym);1609ST_FUNC void gfunc_prolog(Sym *func_sym);
1610ST_FUNC void gfunc_epilog(void);1610ST_FUNC void gfunc_epilog(Sym *func_sym);
1611ST_FUNC void save_return_reg(CType *func_type);
1612ST_FUNC void restore_return_reg(CType *func_type);
1611ST_FUNC void gen_fill_nops(int);1613ST_FUNC void gen_fill_nops(int);
1612ST_FUNC int gjmp(int t);1614ST_FUNC int gjmp(int t);
1613ST_FUNC void gjmp_addr(int a);1615ST_FUNC void gjmp_addr(int a);
tccgen.c+17−11
@@ -6839,10 +6839,14 @@ static void end_switch(void) · 6838 unmodified lines
6839/* ------------------------------------------------------------------------- */6839/* ------------------------------------------------------------------------- */
6840/* __attribute__((cleanup(fn))) */6840/* __attribute__((cleanup(fn))) */
6841 6841
6842static void try_call_scope_cleanup(Sym *stop)6842static 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
6859static void try_call_cleanup_goto(Sym *cleanupstate)6865static 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) */
6967static void leave_scope(struct scope *o)6973static 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 else7136 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);
tccrun.c+2−0
@@ -495,7 +495,9 @@ static void bt_link(TCCState *s1) · 494 unmodified lines
495{495{
496#ifdef CONFIG_TCC_BACKTRACE496#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;
tests/tests2/101_cleanup.c+82−0
@@ -1,9 +1,15 @@
1extern int printf(const char*, ...);1extern int printf(const char*, ...);
2static int glob_i = 0;2static int glob_i = 0;
3 3
4typedef struct { int a; int b; int c; int d; int e; int f; int g; int h; } tstl;
5typedef struct { int a; int b; int c; int d; } tsti;
6typedef struct { double a; double b; } tstd;
7typedef struct { long double a; } tstld;
8
4void incr_glob_i(int *i)9void 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
77void check_oh_i(char *oh_i)84void 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
82void goto_hell(double *f)90void 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
87char *test()96char *test()
@@ -152,6 +161,7 @@ int test3(void) { · 64 unmodified lines
152void cl(int *ip)161void cl(int *ip)
153{162{
154 printf("%d\n", *ip);163 printf("%d\n", *ip);
164 *ip = -1;
155}165}
156 166
157void loop_cleanups(void)167void 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
204void my_cleanup1(int *p) {
205 printf("%d\n", *p);
206 *p = 0x90;
207}
208
209int test_cleanup1(void) {
210 int __attribute__((cleanup(my_cleanup1))) n = 42;
211 return n;
212}
213
214void 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
221tstl 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
228void 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
233tsti 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
239void my_cleanup4(tstd *p) {
240 printf("%g %g\n", p->a, p->b);
241 p->a = 90.0; p->b = 91.0;
242}
243
244tstd test_cleanup4(void) {
245 tstd __attribute__((cleanup(my_cleanup4))) n;
246 n.a = 42.0; n.b = 43.0;
247 return n;
248}
249
250void my_cleanup5(tstld *p) {
251 printf("%Lf\n", p->a);
252 p->a = 90.0;
253}
254
255tstld test_cleanup5(void) {
256 tstld __attribute__((cleanup(my_cleanup5))) n;
257 n.a = 42.0;
258 return n;
259}
260
194int main()261int 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
224void check2(char **hum)305void check2(char **hum)
225{306{
226 printf("str: %s\n", *hum);307 printf("str: %s\n", *hum);
308 *hum = "fail";
227}309}
tests/tests2/101_cleanup.expect+10−0
@@ -48,6 +48,16 @@ str: three · 47 unmodified lines
4840048400
49after break49after break
501000501000
5142
5242
5342 43 44 45 46 47 48 49
5442 43 44 45 46 47 48 49
5542 43 44 45
5642 43 44 45
5742 43
5842 43
5942.000000
6042.000000
51---- 061---- 0
52---- 162---- 1
53str: plop63str: plop
tests/tests2/Makefile+1−0
@@ -31,6 +31,7 @@ ifeq ($(CONFIG_bcheck),no) · 30 unmodified lines
31 SKIP += 116_bound_setjmp2.test31 SKIP += 116_bound_setjmp2.test
32 SKIP += 117_builtins.test32 SKIP += 117_builtins.test
33 SKIP += 126_bound_global.test33 SKIP += 126_bound_global.test
34 SKIP += 132_bound_test.test
34endif35endif
35ifeq ($(CONFIG_dll),no)36ifeq ($(CONFIG_dll),no)
36 SKIP += 113_btdll.test # no shared lib support yet37 SKIP += 113_btdll.test # no shared lib support yet
x86_64-gen.c+57−15
@@ -655,6 +655,50 @@ static void gcall_or_jmp(int is_jmp) · 654 unmodified lines
655 }655 }
656}656}
657 657
658ST_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
680ST_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
660static void gen_bounds_call(int v)704static 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
684static void gen_bounds_epilog(void)728static 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#endif766#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 */
1008void gfunc_epilog(void)1047void 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_BCHECK1055#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#endif1058#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 */
1603void gfunc_epilog(void)1643void gfunc_epilog(Sym *func_sym)
1604{1644{
1605 int v, saved_ind;1645 int v, saved_ind;
1606 1646
1607#ifdef CONFIG_TCC_BCHECK1647#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#endif1650#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 */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t