From 83de532563c6d922c6262dea757a22cb90d06101 Mon Sep 17 00:00:00 2001 From: grischka Date: Sat, 24 May 2025 23:53:37 +0200 Subject: [PATCH] revert "Save registers around attribute cleanup" (almost) In fact, we don't need to save registers. We need to save the symbol if it is a SValue on vstack (the return value in this case) Replaces b6a16e3be4aff2d6b6e4870a1fde5e83707e9be4 --- arm-gen.c | 43 +++++------------------------- arm64-gen.c | 42 +++++------------------------- c67-gen.c | 15 +---------- i386-gen.c | 32 +++++------------------ il-gen.c | 13 +--------- riscv64-gen.c | 57 ++++++---------------------------------- tcc.h | 4 +-- tccgen.c | 46 ++++++++++++++++++-------------- x86_64-gen.c | 72 +++++++++++---------------------------------------- 9 files changed, 73 insertions(+), 251 deletions(-) diff --git a/arm-gen.c b/arm-gen.c index 9aa6e7ae..ec4a2e25 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -837,32 +837,6 @@ static void gcall_or_jmp(int is_jmp) } } -ST_FUNC void save_return_reg(CType *func_type) -{ - int freg = is_float(func_type->t & VT_BTYPE); - int ireg = !freg; - - if ((func_type->t & VT_BTYPE) == VT_STRUCT) - ireg = freg = 1; - if (ireg) - o(0xe92d0003); /* push {r0,r1} */ - if (freg) - o(0xed2d0b04); /* vpush {d0,d1} */ -} - -ST_FUNC void restore_return_reg(CType *func_type) -{ - int freg = is_float(func_type->t & VT_BTYPE); - int ireg = !freg; - - if ((func_type->t & VT_BTYPE) == VT_STRUCT) - ireg = freg = 1; - if (freg) - o(0xecbd0b04); /* vpop {d0,d1} */ - if (ireg) - o(0xe8bd0003); /* pop {r0,r1} */ -} - #if defined(CONFIG_TCC_BCHECK) static void gen_bounds_call(int v) @@ -886,13 +860,12 @@ static void gen_bounds_prolog(void) o(0xe1a00000); /* call __bound_local_new */ } -static void gen_bounds_epilog(Sym *func_sym) +static void gen_bounds_epilog(void) { addr_t saved_ind; addr_t *bounds_ptr; Sym *sym_data; int offset_modified = func_bound_offset != lbounds_section->data_offset; - CType *func_type = &func_sym->type.ref->type; if (!offset_modified && !func_bound_add_epilog) return; @@ -918,16 +891,16 @@ static void gen_bounds_epilog(Sym *func_sym) } /* generate bound check local freeing */ - if (func_type->t != VT_VOID) - save_return_reg(func_type); + o(0xe92d0003); /* push {r0,r1} */ + o(0xed2d0b04); /* vpush {d0,d1} */ o(0xe59f0000); /* ldr r0, [pc] */ o(0xea000000); /* b $+4 */ greloc(cur_text_section, sym_data, ind, R_ARM_REL32); o(-12); /* lbounds_section->data_offset */ o(0xe080000f); /* add r0,r0,pc */ gen_bounds_call(TOK___bound_local_delete); - if (func_type->t != VT_VOID) - restore_return_reg(func_type); + o(0xecbd0b04); /* vpop {d0,d1} */ + o(0xe8bd0003); /* pop {r0,r1} */ } #endif @@ -1535,17 +1508,15 @@ from_stack: } /* generate function epilog */ -void gfunc_epilog(Sym *func_sym) +void gfunc_epilog(void) { uint32_t x; int diff; #ifdef CONFIG_TCC_BCHECK if (tcc_state->do_bounds_check) - gen_bounds_epilog(func_sym); + gen_bounds_epilog(); #endif - func_sym = NULL; - /* Copy float return value to core register if base standard is used and float computation is made with VFP */ #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) diff --git a/arm64-gen.c b/arm64-gen.c index a10a3d72..d15446d3 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -674,32 +674,6 @@ static void arm64_gen_bl_or_b(int b) } } -ST_FUNC void save_return_reg(CType *func_type) -{ - int freg = is_float(func_type->t & VT_BTYPE); - int ireg = !freg; - - if ((func_type->t & VT_BTYPE) == VT_STRUCT) - ireg = freg = 1; - if (ireg) - o(0xa9bf07e0); /* stp x0, x1, [sp, #-16]! */ - if (freg) - o(0xadbf07e0); /* stp q0, q1, [sp, #-32]! */ -} - -ST_FUNC void restore_return_reg(CType *func_type) -{ - int freg = is_float(func_type->t & VT_BTYPE); - int ireg = !freg; - - if ((func_type->t & VT_BTYPE) == VT_STRUCT) - ireg = freg = 1; - if (freg) - o(0xacc107e0); /* ldp q0, q1, [sp], #32 */ - if (ireg) - o(0xa8c107e0); /* ldp x0, x1, [sp], #16 */ -} - #if defined(CONFIG_TCC_BCHECK) static void gen_bounds_call(int v) @@ -722,13 +696,12 @@ static void gen_bounds_prolog(void) o(0xd503201f); /* nop -> call __bound_local_new */ } -static void gen_bounds_epilog(Sym *func_sym) +static void gen_bounds_epilog(void) { addr_t saved_ind; addr_t *bounds_ptr; Sym *sym_data; int offset_modified = func_bound_offset != lbounds_section->data_offset; - CType *func_type = &func_sym->type.ref->type; if (!offset_modified && !func_bound_add_epilog) return; @@ -753,15 +726,15 @@ static void gen_bounds_epilog(Sym *func_sym) } /* generate bound check local freeing */ - if (func_type->t != VT_VOID) - save_return_reg(func_type); + o(0xa9bf07e0); /* stp x0, x1, [sp, #-16]! */ + o(0x3c9f0fe0); /* str q0, [sp, #-16]! */ greloca(cur_text_section, sym_data, ind, R_AARCH64_ADR_GOT_PAGE, 0); o(0x90000000 | 0); // adrp x0, #sym_data greloca(cur_text_section, sym_data, ind, R_AARCH64_LD64_GOT_LO12_NC, 0); o(0xf9400000 | 0 | (0 << 5)); // ld x0,[x0, #sym_data] gen_bounds_call(TOK___bound_local_delete); - if (func_type->t != VT_VOID) - restore_return_reg(func_type); + o(0x3cc107e0); /* ldr q0, [sp], #16 */ + o(0xa8c107e0); /* ldp x0, x1, [sp], #16 */ } #endif @@ -1486,13 +1459,12 @@ ST_FUNC void gfunc_return(CType *func_type) vtop--; } -ST_FUNC void gfunc_epilog(Sym *func_sym) +ST_FUNC void gfunc_epilog(void) { #ifdef CONFIG_TCC_BCHECK if (tcc_state->do_bounds_check) - gen_bounds_epilog(func_sym); + gen_bounds_epilog(); #endif - func_sym = NULL; if (loc) { // Insert instructions to subtract size of stack frame from SP. diff --git a/c67-gen.c b/c67-gen.c index bafedc01..9490a27f 100644 --- a/c67-gen.c +++ b/c67-gen.c @@ -2019,22 +2019,9 @@ void gfunc_prolog(Sym *func_sym) C67_PUSH(C67_B3); } -ST_FUNC void save_return_reg(CType *func_type) -{ - func_type = NULL; - // TODO -} - -ST_FUNC void restore_return_reg(CType *func_type) -{ - func_type = NULL; - // TODO -} - /* generate function epilog */ -void gfunc_epilog(Sym *func_sym) +void gfunc_epilog(void) { - func_sym = NULL; { int local = (-loc + 7) & -8; // stack must stay aligned to 8 bytes for LDDW instr C67_POP(C67_B3); diff --git a/i386-gen.c b/i386-gen.c index 5e9a9e5c..5814a398 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -104,7 +104,7 @@ static addr_t func_bound_offset; static unsigned long func_bound_ind; ST_DATA int func_bound_add_epilog; static void gen_bounds_prolog(void); -static void gen_bounds_epilog(Sym *func_sym); +static void gen_bounds_epilog(void); #endif /* XXX: make it faster ? */ @@ -595,15 +595,14 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) } /* generate function epilog */ -ST_FUNC void gfunc_epilog(Sym *func_sym) +ST_FUNC void gfunc_epilog(void) { addr_t v, saved_ind; #ifdef CONFIG_TCC_BCHECK if (tcc_state->do_bounds_check) - gen_bounds_epilog(func_sym); + gen_bounds_epilog(); #endif - func_sym = NULL; /* align local size to word & save local variables */ v = (-loc + 3) & -4; @@ -1041,22 +1040,6 @@ ST_FUNC void ggoto(void) vtop--; } -ST_FUNC void save_return_reg(CType *func_type) -{ - int ireg = !is_float(func_type->t & VT_BTYPE); - - if (ireg) - o(0x5250); /* push %rax; %push %rdx */ -} - -ST_FUNC void restore_return_reg(CType *func_type) -{ - int ireg = !is_float(func_type->t & VT_BTYPE); - - if (ireg) - o(0x585a); /* pop %rdx; pop %rax */ -} - /* bound check support functions */ #ifdef CONFIG_TCC_BCHECK @@ -1070,13 +1053,12 @@ static void gen_bounds_prolog(void) oad(0xb8, 0); /* call to function */ } -static void gen_bounds_epilog(Sym *func_sym) +static void gen_bounds_epilog(void) { addr_t saved_ind; addr_t *bounds_ptr; Sym *sym_data; int offset_modified = func_bound_offset != lbounds_section->data_offset; - CType *func_type = &func_sym->type.ref->type; if (!offset_modified && !func_bound_add_epilog) return; @@ -1099,13 +1081,11 @@ static void gen_bounds_epilog(Sym *func_sym) } /* generate bound check local freeing */ - if (func_type->t != VT_VOID) - save_return_reg(func_type); + o(0x5250); /* save returned value, if any */ greloc(cur_text_section, sym_data, ind + 1, R_386_32); oad(0xb8, 0); /* mov %eax, xxx */ gen_static_call(TOK___bound_local_delete); - if (func_type->t != VT_VOID) - restore_return_reg(func_type); + o(0x585a); /* restore returned value, if any */ } #endif diff --git a/il-gen.c b/il-gen.c index a00d6786..bb670ccb 100644 --- a/il-gen.c +++ b/il-gen.c @@ -457,20 +457,9 @@ void gfunc_prolog(int t) } } -void save_return_reg(CType *func_type) -{ - func_type = NULL; -} - -void restore_return_reg(CType *func_type) -{ - func_type = NULL; -} - /* generate function epilog */ -void gfunc_epilog(Sym *func_sym) +void gfunc_epilog(void) { - func_sym = NULL; out_op(IL_OP_RET); fprintf(il_outfile, "}\n\n"); } diff --git a/riscv64-gen.c b/riscv64-gen.c index c38c996f..99c94dc3 100644 --- a/riscv64-gen.c +++ b/riscv64-gen.c @@ -436,46 +436,6 @@ static void gcall_or_jmp(int docall) } } -ST_FUNC void save_return_reg(CType *func_type) -{ - int freg = is_float(func_type->t & VT_BTYPE) && - (func_type->t & VT_BTYPE) != VT_LDOUBLE; - int ireg = !freg; - - if ((func_type->t & VT_BTYPE) == VT_STRUCT) - ireg = freg = 1; - if (ireg && freg) { - o(0xe02a1101); /* addi sp,sp,-32 sd a0,0(sp) */ - o(0xa82ae42e); /* sd a1,8(sp) fsd fa0,16(sp) */ - } - else if (ireg) { - o(0xe02a1141); /* addi sp,sp,-16 sd a0,0(sp) */ - o(0x0001e42e); /* sd a1,8(sp) nop */ - } - else if (freg) - o(0xa02a1141); /* addi sp,sp,-16 fsd fa0,0(sp) */ -} - -ST_FUNC void restore_return_reg(CType *func_type) -{ - int freg = is_float(func_type->t & VT_BTYPE) && - (func_type->t & VT_BTYPE) != VT_LDOUBLE; - int ireg = !freg; - - if ((func_type->t & VT_BTYPE) == VT_STRUCT) - ireg = freg = 1; - if (ireg && freg) { - o(0x65a26502); /* ld a0,0(sp) ld a1,8(sp) */ - o(0x61052542); /* fld fa0,16(sp) addi sp,sp,32 */ - } - else if (ireg) { - o(0x65a26502); /* ld a0,0(sp) ld a1,8(sp) */ - o(0x00010141); /* addi sp,sp,16 nop */ - } - else if (freg) - o(0x01412502); /* fld fa0,0(sp) addi sp,sp,16 */ -} - #if defined(CONFIG_TCC_BCHECK) static void gen_bounds_call(int v) @@ -499,14 +459,14 @@ static void gen_bounds_prolog(void) o(0x00000013); } -static void gen_bounds_epilog(Sym *func_sym) +static void gen_bounds_epilog(void) { addr_t saved_ind; addr_t *bounds_ptr; Sym *sym_data; Sym label = {0}; + int offset_modified = func_bound_offset != lbounds_section->data_offset; - CType *func_type = &func_sym->type.ref->type; if (!offset_modified && !func_bound_add_epilog) return; @@ -534,16 +494,16 @@ static void gen_bounds_epilog(Sym *func_sym) } /* generate bound check local freeing */ - if (func_type->t != VT_VOID) - save_return_reg(func_type); + o(0xe02a1101); /* addi sp,sp,-32 sd a0,0(sp) */ + o(0xa82ae42e); /* sd a1,8(sp) fsd fa0,16(sp) */ put_extern_sym(&label, cur_text_section, ind, 0); greloca(cur_text_section, sym_data, ind, R_RISCV_GOT_HI20, 0); o(0x17 | (10 << 7)); // auipc a0, 0 %pcrel_hi(sym)+addend greloca(cur_text_section, &label, ind, R_RISCV_PCREL_LO12_I, 0); EI(0x03, 3, 10, 10, 0); // ld a0, 0(a0) gen_bounds_call(TOK___bound_local_delete); - if (func_type->t != VT_VOID) - restore_return_reg(func_type); + o(0x65a26502); /* ld a0,0(sp) ld a1,8(sp) */ + o(0x61052542); /* fld fa0,16(sp) addi sp,sp,32 */ } #endif @@ -933,15 +893,14 @@ ST_FUNC void arch_transfer_ret_regs(int aftercall) vtop--; } -ST_FUNC void gfunc_epilog(Sym *func_sym) +ST_FUNC void gfunc_epilog(void) { int v, saved_ind, d, large_ofs_ind; #ifdef CONFIG_TCC_BCHECK if (tcc_state->do_bounds_check) - gen_bounds_epilog(func_sym); + gen_bounds_epilog(); #endif - func_sym = NULL; loc = (loc - num_va_regs * 8); d = v = (-loc + 15) & -16; diff --git a/tcc.h b/tcc.h index debc96d7..452a723a 100644 --- a/tcc.h +++ b/tcc.h @@ -1607,9 +1607,7 @@ ST_FUNC void store(int r, SValue *v); ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize); ST_FUNC void gfunc_call(int nb_args); ST_FUNC void gfunc_prolog(Sym *func_sym); -ST_FUNC void gfunc_epilog(Sym *func_sym); -ST_FUNC void save_return_reg(CType *func_type); -ST_FUNC void restore_return_reg(CType *func_type); +ST_FUNC void gfunc_epilog(void); ST_FUNC void gen_fill_nops(int); ST_FUNC int gjmp(int t); ST_FUNC void gjmp_addr(int a); diff --git a/tccgen.c b/tccgen.c index a1b1b80c..5829037c 100644 --- a/tccgen.c +++ b/tccgen.c @@ -6839,18 +6839,28 @@ static void end_switch(void) /* ------------------------------------------------------------------------- */ /* __attribute__((cleanup(fn))) */ -static void try_call_scope_cleanup(Sym *stop, CType *func_type) +/* save SValue of symbol to local stack */ +static void save_cleanup_sym(Sym *s) +{ + SValue *sv = vtop; + while (sv >= vstack) { + if (sv->sym == s) { + int align, size = type_size(&sv->type, &align); + loc = (loc - size) & -align; + vset(&sv->type, VT_LOCAL | VT_LVAL, loc); + vpushv(sv), *sv = vtop[-1], vstore(), --vtop; + } + --sv; + } +} + +static void try_call_scope_cleanup(Sym *stop) { Sym *cls = cur_scope->cl.s; - - if (cls == stop) - func_type = NULL; - if (func_type && func_type->t != VT_VOID) - save_return_reg(func_type); for (; cls != stop; cls = cls->next) { Sym *fs = cls->cleanup_func; Sym *vs = cls->prev_tok; - + save_cleanup_sym(vs); vpushsym(&fs->type, fs); vset(&vs->type, vs->r, vs->c); vtop->sym = vs; @@ -6858,8 +6868,6 @@ static void try_call_scope_cleanup(Sym *stop, CType *func_type) gaddrof(); gfunc_call(1); } - if (func_type && func_type->t != VT_VOID) - restore_return_reg(func_type); } static void try_call_cleanup_goto(Sym *cleanupstate) @@ -6879,7 +6887,7 @@ static void try_call_cleanup_goto(Sym *cleanupstate) for (; cc != oc; cc = cc->next, oc = oc->next, --ccd) ; - try_call_scope_cleanup(cc, NULL); + try_call_scope_cleanup(cc); } /* call 'func' for each __attribute__((cleanup(func))) */ @@ -6893,7 +6901,7 @@ static void block_cleanup(struct scope *o) if (!jmp) jmp = gjmp(0); gsym(pcl->jnext); - try_call_scope_cleanup(o->cl.s, NULL); + try_call_scope_cleanup(o->cl.s); pcl->jnext = gjmp(0); if (!o->cl.n) goto remove_pending; @@ -6906,7 +6914,7 @@ static void block_cleanup(struct scope *o) } } gsym(jmp); - try_call_scope_cleanup(o->cl.s, NULL); + try_call_scope_cleanup(o->cl.s); } /* ------------------------------------------------------------------------- */ @@ -6970,11 +6978,11 @@ static void prev_scope(struct scope *o, int is_expr) } /* leave a scope via break/continue(/goto) */ -static void leave_scope(struct scope *o, CType *func_type) +static void leave_scope(struct scope *o) { if (!o) return; - try_call_scope_cleanup(o->cl.s, func_type); + try_call_scope_cleanup(o->cl.s); vla_leave(o); } @@ -7116,9 +7124,9 @@ again: tcc_warning("'return' with no value"); b = 0; } + leave_scope(root_scope); if (b) gfunc_return(&func_vt); - leave_scope(root_scope, &func_vt); skip(';'); /* jump unless last stmt in top-level block */ if (tok != '}' || local_scope != 1) @@ -7132,9 +7140,9 @@ again: if (!cur_scope->bsym) tcc_error("cannot break"); if (cur_switch && cur_scope->bsym == cur_switch->bsym) - leave_scope(cur_switch->scope, NULL); + leave_scope(cur_switch->scope); else - leave_scope(loop_scope, NULL); + leave_scope(loop_scope); *cur_scope->bsym = gjmp(*cur_scope->bsym); skip(';'); @@ -7142,7 +7150,7 @@ again: /* compute jump */ if (!cur_scope->csym) tcc_error("cannot continue"); - leave_scope(loop_scope, NULL); + leave_scope(loop_scope); *cur_scope->csym = gjmp(*cur_scope->csym); skip(';'); @@ -8406,7 +8414,7 @@ static void gen_function(Sym *sym) /* reset local stack */ pop_local_syms(NULL, 0); tcc_debug_prolog_epilog(tcc_state, 1); - gfunc_epilog(sym); + gfunc_epilog(); /* end of function */ tcc_debug_funcend(tcc_state, ind - func_ind); diff --git a/x86_64-gen.c b/x86_64-gen.c index d4c4c650..3a430585 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -655,50 +655,6 @@ static void gcall_or_jmp(int is_jmp) } } -ST_FUNC void save_return_reg(CType *func_type) -{ - int freg = is_float(func_type->t & VT_BTYPE); - int ireg = !freg; - - if ((func_type->t & VT_BTYPE) == VT_STRUCT) - ireg = freg = 1; - if (ireg) - o(0x5250); /* push %rax; %push %rdx */ - if (freg) { - if ((func_type->t & VT_BTYPE) == VT_LDOUBLE || - (func_type->t & VT_BTYPE) == VT_STRUCT) { - o(0x10ec8348); /* sub $16,%rsp */ - o(0x243cdb); /* fstpt (%rsp) */ - } - o(0x20ec8348); /* sub $32,%rsp */ - o(0x290f); /* movaps %xmm0,0x10(%rsp) */ - o(0x102444); - o(0x240c290f); /* movaps %xmm1,(%rsp) */ - } -} - -ST_FUNC void restore_return_reg(CType *func_type) -{ - int freg = is_float(func_type->t & VT_BTYPE); - int ireg = !freg; - - if ((func_type->t & VT_BTYPE) == VT_STRUCT) - ireg = freg = 1; - if (freg) { - o(0x280f); /* movaps 0x10(%rsp),%xmm0 */ - o(0x102444); - o(0x240c280f); /* movaps (%rsp),%xmm1 */ - o(0x20c48348); /* add $32,%rsp */ - if ((func_type->t & VT_BTYPE) == VT_LDOUBLE || - (func_type->t & VT_BTYPE) == VT_STRUCT) { - o(0x242cdb); /* fldt (%rsp) */ - o(0x10c48348); /* add $16,%rsp */ - } - } - if (ireg) - o(0x585a); /* pop %rdx; pop %rax */ -} - #if defined(CONFIG_TCC_BCHECK) static void gen_bounds_call(int v) @@ -725,13 +681,12 @@ static void gen_bounds_prolog(void) oad(0xb8, 0); /* call to function */ } -static void gen_bounds_epilog(Sym *func_sym) +static void gen_bounds_epilog(void) { addr_t saved_ind; addr_t *bounds_ptr; Sym *sym_data; int offset_modified = func_bound_offset != lbounds_section->data_offset; - CType *func_type = &func_sym->type.ref->type; if (!offset_modified && !func_bound_add_epilog) return; @@ -754,14 +709,20 @@ static void gen_bounds_epilog(Sym *func_sym) } /* generate bound check local freeing */ - if (func_type->t != VT_VOID) - save_return_reg(func_type); + o(0x5250); /* save returned value, if any */ + o(0x20ec8348); /* sub $32,%rsp */ + o(0x290f); /* movaps %xmm0,0x10(%rsp) */ + o(0x102444); + o(0x240c290f); /* movaps %xmm1,(%rsp) */ greloca(cur_text_section, sym_data, ind + 3, R_X86_64_PC32, -4); o(0x0d8d48 + ((TREG_FASTCALL_1 == TREG_RDI) * 0x300000)); /* lea xxx(%rip), %rcx/rdi */ gen_le32 (0); gen_bounds_call(TOK___bound_local_delete); - if (func_type->t != VT_VOID) - restore_return_reg(func_type); + o(0x280f); /* movaps 0x10(%rsp),%xmm0 */ + o(0x102444); + o(0x240c280f); /* movaps (%rsp),%xmm1 */ + o(0x20c48348); /* add $32,%rsp */ + o(0x585a); /* restore returned value, if any */ } #endif @@ -1044,7 +1005,7 @@ void gfunc_prolog(Sym *func_sym) } /* generate function epilog */ -void gfunc_epilog(Sym *func_sym) +void gfunc_epilog(void) { int v, start; @@ -1054,9 +1015,8 @@ void gfunc_epilog(Sym *func_sym) #ifdef CONFIG_TCC_BCHECK if (tcc_state->do_bounds_check) - gen_bounds_epilog(func_sym); + gen_bounds_epilog(); #endif - func_sym = NULL; o(0xc9); /* leave */ if (func_ret_sub == 0) { @@ -1640,16 +1600,14 @@ void gfunc_prolog(Sym *func_sym) } /* generate function epilog */ -void gfunc_epilog(Sym *func_sym) +void gfunc_epilog(void) { int v, saved_ind; #ifdef CONFIG_TCC_BCHECK if (tcc_state->do_bounds_check) - gen_bounds_epilog(func_sym); + gen_bounds_epilog(); #endif - func_sym = NULL; - o(0xc9); /* leave */ if (func_ret_sub == 0) { o(0xc3); /* ret */