revert "Save registers around attribute cleanup" (almost)
Some checks failed
build and test / test-x86_64-linux (push) Has been cancelled
build and test / test-x86_64-osx (push) Has been cancelled
build and test / test-aarch64-osx (push) Has been cancelled
build and test / test-x86-win32 (push) Has been cancelled
build and test / test-armv7-linux (push) Has been cancelled
build and test / test-aarch64-linux (push) Has been cancelled
build and test / test-riscv64-linux (push) Has been cancelled

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) #if defined(CONFIG_TCC_BCHECK)
static void gen_bounds_call(int v) static void gen_bounds_call(int v)
@ -886,13 +860,12 @@ static void gen_bounds_prolog(void)
o(0xe1a00000); /* call __bound_local_new */ 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 saved_ind;
addr_t *bounds_ptr; addr_t *bounds_ptr;
Sym *sym_data; Sym *sym_data;
int offset_modified = func_bound_offset != lbounds_section->data_offset; 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) if (!offset_modified && !func_bound_add_epilog)
return; return;
@ -918,16 +891,16 @@ static void gen_bounds_epilog(Sym *func_sym)
} }
/* generate bound check local freeing */ /* generate bound check local freeing */
if (func_type->t != VT_VOID) o(0xe92d0003); /* push {r0,r1} */
save_return_reg(func_type); o(0xed2d0b04); /* vpush {d0,d1} */
o(0xe59f0000); /* ldr r0, [pc] */ o(0xe59f0000); /* ldr r0, [pc] */
o(0xea000000); /* b $+4 */ o(0xea000000); /* b $+4 */
greloc(cur_text_section, sym_data, ind, R_ARM_REL32); greloc(cur_text_section, sym_data, ind, R_ARM_REL32);
o(-12); /* lbounds_section->data_offset */ o(-12); /* lbounds_section->data_offset */
o(0xe080000f); /* add r0,r0,pc */ o(0xe080000f); /* add r0,r0,pc */
gen_bounds_call(TOK___bound_local_delete); gen_bounds_call(TOK___bound_local_delete);
if (func_type->t != VT_VOID) o(0xecbd0b04); /* vpop {d0,d1} */
restore_return_reg(func_type); o(0xe8bd0003); /* pop {r0,r1} */
} }
#endif #endif
@ -1535,17 +1508,15 @@ from_stack:
} }
/* generate function epilog */ /* generate function epilog */
void gfunc_epilog(Sym *func_sym) void gfunc_epilog(void)
{ {
uint32_t x; uint32_t x;
int diff; int diff;
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check) if (tcc_state->do_bounds_check)
gen_bounds_epilog(func_sym); gen_bounds_epilog();
#endif #endif
func_sym = NULL;
/* Copy float return value to core register if base standard is used and /* Copy float return value to core register if base standard is used and
float computation is made with VFP */ float computation is made with VFP */
#if defined(TCC_ARM_EABI) && defined(TCC_ARM_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) #if defined(CONFIG_TCC_BCHECK)
static void gen_bounds_call(int v) static void gen_bounds_call(int v)
@ -722,13 +696,12 @@ static void gen_bounds_prolog(void)
o(0xd503201f); /* nop -> call __bound_local_new */ 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 saved_ind;
addr_t *bounds_ptr; addr_t *bounds_ptr;
Sym *sym_data; Sym *sym_data;
int offset_modified = func_bound_offset != lbounds_section->data_offset; 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) if (!offset_modified && !func_bound_add_epilog)
return; return;
@ -753,15 +726,15 @@ static void gen_bounds_epilog(Sym *func_sym)
} }
/* generate bound check local freeing */ /* generate bound check local freeing */
if (func_type->t != VT_VOID) o(0xa9bf07e0); /* stp x0, x1, [sp, #-16]! */
save_return_reg(func_type); o(0x3c9f0fe0); /* str q0, [sp, #-16]! */
greloca(cur_text_section, sym_data, ind, R_AARCH64_ADR_GOT_PAGE, 0); greloca(cur_text_section, sym_data, ind, R_AARCH64_ADR_GOT_PAGE, 0);
o(0x90000000 | 0); // adrp x0, #sym_data o(0x90000000 | 0); // adrp x0, #sym_data
greloca(cur_text_section, sym_data, ind, R_AARCH64_LD64_GOT_LO12_NC, 0); greloca(cur_text_section, sym_data, ind, R_AARCH64_LD64_GOT_LO12_NC, 0);
o(0xf9400000 | 0 | (0 << 5)); // ld x0,[x0, #sym_data] o(0xf9400000 | 0 | (0 << 5)); // ld x0,[x0, #sym_data]
gen_bounds_call(TOK___bound_local_delete); gen_bounds_call(TOK___bound_local_delete);
if (func_type->t != VT_VOID) o(0x3cc107e0); /* ldr q0, [sp], #16 */
restore_return_reg(func_type); o(0xa8c107e0); /* ldp x0, x1, [sp], #16 */
} }
#endif #endif
@ -1486,13 +1459,12 @@ ST_FUNC void gfunc_return(CType *func_type)
vtop--; vtop--;
} }
ST_FUNC void gfunc_epilog(Sym *func_sym) ST_FUNC void gfunc_epilog(void)
{ {
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check) if (tcc_state->do_bounds_check)
gen_bounds_epilog(func_sym); gen_bounds_epilog();
#endif #endif
func_sym = NULL;
if (loc) { if (loc) {
// Insert instructions to subtract size of stack frame from SP. // 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); 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 */ /* 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 int local = (-loc + 7) & -8; // stack must stay aligned to 8 bytes for LDDW instr
C67_POP(C67_B3); C67_POP(C67_B3);

View File

@ -104,7 +104,7 @@ static addr_t func_bound_offset;
static unsigned long func_bound_ind; static unsigned long func_bound_ind;
ST_DATA int func_bound_add_epilog; ST_DATA int func_bound_add_epilog;
static void gen_bounds_prolog(void); static void gen_bounds_prolog(void);
static void gen_bounds_epilog(Sym *func_sym); static void gen_bounds_epilog(void);
#endif #endif
/* XXX: make it faster ? */ /* XXX: make it faster ? */
@ -595,15 +595,14 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
} }
/* generate function epilog */ /* generate function epilog */
ST_FUNC void gfunc_epilog(Sym *func_sym) ST_FUNC void gfunc_epilog(void)
{ {
addr_t v, saved_ind; addr_t v, saved_ind;
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check) if (tcc_state->do_bounds_check)
gen_bounds_epilog(func_sym); gen_bounds_epilog();
#endif #endif
func_sym = NULL;
/* align local size to word & save local variables */ /* align local size to word & save local variables */
v = (-loc + 3) & -4; v = (-loc + 3) & -4;
@ -1041,22 +1040,6 @@ ST_FUNC void ggoto(void)
vtop--; 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 */ /* bound check support functions */
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
@ -1070,13 +1053,12 @@ static void gen_bounds_prolog(void)
oad(0xb8, 0); /* call to function */ 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 saved_ind;
addr_t *bounds_ptr; addr_t *bounds_ptr;
Sym *sym_data; Sym *sym_data;
int offset_modified = func_bound_offset != lbounds_section->data_offset; 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) if (!offset_modified && !func_bound_add_epilog)
return; return;
@ -1099,13 +1081,11 @@ static void gen_bounds_epilog(Sym *func_sym)
} }
/* generate bound check local freeing */ /* generate bound check local freeing */
if (func_type->t != VT_VOID) o(0x5250); /* save returned value, if any */
save_return_reg(func_type);
greloc(cur_text_section, sym_data, ind + 1, R_386_32); greloc(cur_text_section, sym_data, ind + 1, R_386_32);
oad(0xb8, 0); /* mov %eax, xxx */ oad(0xb8, 0); /* mov %eax, xxx */
gen_static_call(TOK___bound_local_delete); gen_static_call(TOK___bound_local_delete);
if (func_type->t != VT_VOID) o(0x585a); /* restore returned value, if any */
restore_return_reg(func_type);
} }
#endif #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 */ /* generate function epilog */
void gfunc_epilog(Sym *func_sym) void gfunc_epilog(void)
{ {
func_sym = NULL;
out_op(IL_OP_RET); out_op(IL_OP_RET);
fprintf(il_outfile, "}\n\n"); 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) #if defined(CONFIG_TCC_BCHECK)
static void gen_bounds_call(int v) static void gen_bounds_call(int v)
@ -499,14 +459,14 @@ static void gen_bounds_prolog(void)
o(0x00000013); o(0x00000013);
} }
static void gen_bounds_epilog(Sym *func_sym) static void gen_bounds_epilog(void)
{ {
addr_t saved_ind; addr_t saved_ind;
addr_t *bounds_ptr; addr_t *bounds_ptr;
Sym *sym_data; Sym *sym_data;
Sym label = {0}; Sym label = {0};
int offset_modified = func_bound_offset != lbounds_section->data_offset; 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) if (!offset_modified && !func_bound_add_epilog)
return; return;
@ -534,16 +494,16 @@ static void gen_bounds_epilog(Sym *func_sym)
} }
/* generate bound check local freeing */ /* generate bound check local freeing */
if (func_type->t != VT_VOID) o(0xe02a1101); /* addi sp,sp,-32 sd a0,0(sp) */
save_return_reg(func_type); o(0xa82ae42e); /* sd a1,8(sp) fsd fa0,16(sp) */
put_extern_sym(&label, cur_text_section, ind, 0); put_extern_sym(&label, cur_text_section, ind, 0);
greloca(cur_text_section, sym_data, ind, R_RISCV_GOT_HI20, 0); greloca(cur_text_section, sym_data, ind, R_RISCV_GOT_HI20, 0);
o(0x17 | (10 << 7)); // auipc a0, 0 %pcrel_hi(sym)+addend o(0x17 | (10 << 7)); // auipc a0, 0 %pcrel_hi(sym)+addend
greloca(cur_text_section, &label, ind, R_RISCV_PCREL_LO12_I, 0); greloca(cur_text_section, &label, ind, R_RISCV_PCREL_LO12_I, 0);
EI(0x03, 3, 10, 10, 0); // ld a0, 0(a0) EI(0x03, 3, 10, 10, 0); // ld a0, 0(a0)
gen_bounds_call(TOK___bound_local_delete); gen_bounds_call(TOK___bound_local_delete);
if (func_type->t != VT_VOID) o(0x65a26502); /* ld a0,0(sp) ld a1,8(sp) */
restore_return_reg(func_type); o(0x61052542); /* fld fa0,16(sp) addi sp,sp,32 */
} }
#endif #endif
@ -933,15 +893,14 @@ ST_FUNC void arch_transfer_ret_regs(int aftercall)
vtop--; vtop--;
} }
ST_FUNC void gfunc_epilog(Sym *func_sym) ST_FUNC void gfunc_epilog(void)
{ {
int v, saved_ind, d, large_ofs_ind; int v, saved_ind, d, large_ofs_ind;
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check) if (tcc_state->do_bounds_check)
gen_bounds_epilog(func_sym); gen_bounds_epilog();
#endif #endif
func_sym = NULL;
loc = (loc - num_va_regs * 8); loc = (loc - num_va_regs * 8);
d = v = (-loc + 15) & -16; 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 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_call(int nb_args);
ST_FUNC void gfunc_prolog(Sym *func_sym); ST_FUNC void gfunc_prolog(Sym *func_sym);
ST_FUNC void gfunc_epilog(Sym *func_sym); ST_FUNC void gfunc_epilog(void);
ST_FUNC void save_return_reg(CType *func_type);
ST_FUNC void restore_return_reg(CType *func_type);
ST_FUNC void gen_fill_nops(int); ST_FUNC void gen_fill_nops(int);
ST_FUNC int gjmp(int t); ST_FUNC int gjmp(int t);
ST_FUNC void gjmp_addr(int a); ST_FUNC void gjmp_addr(int a);

View File

@ -6839,18 +6839,28 @@ static void end_switch(void)
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/* __attribute__((cleanup(fn))) */ /* __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; 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) { for (; cls != stop; cls = cls->next) {
Sym *fs = cls->cleanup_func; Sym *fs = cls->cleanup_func;
Sym *vs = cls->prev_tok; Sym *vs = cls->prev_tok;
save_cleanup_sym(vs);
vpushsym(&fs->type, fs); vpushsym(&fs->type, fs);
vset(&vs->type, vs->r, vs->c); vset(&vs->type, vs->r, vs->c);
vtop->sym = vs; vtop->sym = vs;
@ -6858,8 +6868,6 @@ static void try_call_scope_cleanup(Sym *stop, CType *func_type)
gaddrof(); gaddrof();
gfunc_call(1); gfunc_call(1);
} }
if (func_type && func_type->t != VT_VOID)
restore_return_reg(func_type);
} }
static void try_call_cleanup_goto(Sym *cleanupstate) 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) 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))) */ /* call 'func' for each __attribute__((cleanup(func))) */
@ -6893,7 +6901,7 @@ static void block_cleanup(struct scope *o)
if (!jmp) if (!jmp)
jmp = gjmp(0); jmp = gjmp(0);
gsym(pcl->jnext); gsym(pcl->jnext);
try_call_scope_cleanup(o->cl.s, NULL); try_call_scope_cleanup(o->cl.s);
pcl->jnext = gjmp(0); pcl->jnext = gjmp(0);
if (!o->cl.n) if (!o->cl.n)
goto remove_pending; goto remove_pending;
@ -6906,7 +6914,7 @@ static void block_cleanup(struct scope *o)
} }
} }
gsym(jmp); 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) */ /* 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) if (!o)
return; return;
try_call_scope_cleanup(o->cl.s, func_type); try_call_scope_cleanup(o->cl.s);
vla_leave(o); vla_leave(o);
} }
@ -7116,9 +7124,9 @@ again:
tcc_warning("'return' with no value"); tcc_warning("'return' with no value");
b = 0; b = 0;
} }
leave_scope(root_scope);
if (b) if (b)
gfunc_return(&func_vt); gfunc_return(&func_vt);
leave_scope(root_scope, &func_vt);
skip(';'); skip(';');
/* jump unless last stmt in top-level block */ /* jump unless last stmt in top-level block */
if (tok != '}' || local_scope != 1) if (tok != '}' || local_scope != 1)
@ -7132,9 +7140,9 @@ again:
if (!cur_scope->bsym) if (!cur_scope->bsym)
tcc_error("cannot break"); tcc_error("cannot break");
if (cur_switch && cur_scope->bsym == cur_switch->bsym) if (cur_switch && cur_scope->bsym == cur_switch->bsym)
leave_scope(cur_switch->scope, NULL); leave_scope(cur_switch->scope);
else else
leave_scope(loop_scope, NULL); leave_scope(loop_scope);
*cur_scope->bsym = gjmp(*cur_scope->bsym); *cur_scope->bsym = gjmp(*cur_scope->bsym);
skip(';'); skip(';');
@ -7142,7 +7150,7 @@ again:
/* compute jump */ /* compute jump */
if (!cur_scope->csym) if (!cur_scope->csym)
tcc_error("cannot continue"); tcc_error("cannot continue");
leave_scope(loop_scope, NULL); leave_scope(loop_scope);
*cur_scope->csym = gjmp(*cur_scope->csym); *cur_scope->csym = gjmp(*cur_scope->csym);
skip(';'); skip(';');
@ -8406,7 +8414,7 @@ static void gen_function(Sym *sym)
/* reset local stack */ /* reset local stack */
pop_local_syms(NULL, 0); pop_local_syms(NULL, 0);
tcc_debug_prolog_epilog(tcc_state, 1); tcc_debug_prolog_epilog(tcc_state, 1);
gfunc_epilog(sym); gfunc_epilog();
/* end of function */ /* end of function */
tcc_debug_funcend(tcc_state, ind - func_ind); 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) #if defined(CONFIG_TCC_BCHECK)
static void gen_bounds_call(int v) static void gen_bounds_call(int v)
@ -725,13 +681,12 @@ static void gen_bounds_prolog(void)
oad(0xb8, 0); /* call to function */ 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 saved_ind;
addr_t *bounds_ptr; addr_t *bounds_ptr;
Sym *sym_data; Sym *sym_data;
int offset_modified = func_bound_offset != lbounds_section->data_offset; 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) if (!offset_modified && !func_bound_add_epilog)
return; return;
@ -754,14 +709,20 @@ static void gen_bounds_epilog(Sym *func_sym)
} }
/* generate bound check local freeing */ /* generate bound check local freeing */
if (func_type->t != VT_VOID) o(0x5250); /* save returned value, if any */
save_return_reg(func_type); 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); 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 */ o(0x0d8d48 + ((TREG_FASTCALL_1 == TREG_RDI) * 0x300000)); /* lea xxx(%rip), %rcx/rdi */
gen_le32 (0); gen_le32 (0);
gen_bounds_call(TOK___bound_local_delete); gen_bounds_call(TOK___bound_local_delete);
if (func_type->t != VT_VOID) o(0x280f); /* movaps 0x10(%rsp),%xmm0 */
restore_return_reg(func_type); o(0x102444);
o(0x240c280f); /* movaps (%rsp),%xmm1 */
o(0x20c48348); /* add $32,%rsp */
o(0x585a); /* restore returned value, if any */
} }
#endif #endif
@ -1044,7 +1005,7 @@ void gfunc_prolog(Sym *func_sym)
} }
/* generate function epilog */ /* generate function epilog */
void gfunc_epilog(Sym *func_sym) void gfunc_epilog(void)
{ {
int v, start; int v, start;
@ -1054,9 +1015,8 @@ void gfunc_epilog(Sym *func_sym)
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check) if (tcc_state->do_bounds_check)
gen_bounds_epilog(func_sym); gen_bounds_epilog();
#endif #endif
func_sym = NULL;
o(0xc9); /* leave */ o(0xc9); /* leave */
if (func_ret_sub == 0) { if (func_ret_sub == 0) {
@ -1640,16 +1600,14 @@ void gfunc_prolog(Sym *func_sym)
} }
/* generate function epilog */ /* generate function epilog */
void gfunc_epilog(Sym *func_sym) void gfunc_epilog(void)
{ {
int v, saved_ind; int v, saved_ind;
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check) if (tcc_state->do_bounds_check)
gen_bounds_epilog(func_sym); gen_bounds_epilog();
#endif #endif
func_sym = NULL;
o(0xc9); /* leave */ o(0xc9); /* leave */
if (func_ret_sub == 0) { if (func_ret_sub == 0) {
o(0xc3); /* ret */ o(0xc3); /* ret */