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 b6a16e3be4
This commit is contained in:
grischka
2025-05-24 23:53:37 +02:00
parent b6a16e3be4
commit 83de532563
9 changed files with 73 additions and 251 deletions

View File

@@ -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)

View File

@@ -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.

View File

@@ -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);

View File

@@ -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

View File

@@ -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");
}

View File

@@ -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;

4
tcc.h
View File

@@ -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);

View File

@@ -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);

View File

@@ -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 */