aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arm-gen.c34
-rw-r--r--c67-gen.c3
-rw-r--r--i386-gen.c3
-rw-r--r--il-gen.c1
-rw-r--r--tcc.h3
-rw-r--r--tccgen.c11
-rw-r--r--x86_64-gen.c3
7 files changed, 35 insertions, 23 deletions
diff --git a/arm-gen.c b/arm-gen.c
index eecb7d2..9e6c638 100644
--- a/arm-gen.c
+++ b/arm-gen.c
@@ -839,12 +839,12 @@ int floats_in_core_regs(SValue *sval)
/* Return the number of registers needed to return the struct, or 0 if
returning via struct pointer. */
-ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align) {
#ifdef TCC_ARM_EABI
int size, align;
size = type_size(vt, &align);
#ifdef TCC_ARM_HARDFLOAT
- if (is_float(vt->t) || is_hgen_float_aggr(vt)) {
+ if (!variadic && (is_float(vt->t) || is_hgen_float_aggr(vt))) {
*ret_align = 8;
ret->ref = NULL;
ret->t = VT_DOUBLE;
@@ -1221,21 +1221,19 @@ void gfunc_call(int nb_args)
void gfunc_prolog(CType *func_type)
{
Sym *sym,*sym2;
- int n,nf,size,align, variadic, struct_ret = 0;
+ int n, nf, size, align, struct_ret = 0;
#ifdef TCC_ARM_HARDFLOAT
struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
#endif
+ CType ret_type;
sym = func_type->ref;
func_vt = sym->type;
+ func_var = (func_type->ref->c == FUNC_ELLIPSIS);
n = nf = 0;
- variadic = (func_type->ref->c == FUNC_ELLIPSIS);
- if((func_vt.t & VT_BTYPE) == VT_STRUCT
-#ifdef TCC_ARM_HARDFLOAT
- && (variadic || !is_hgen_float_aggr(&func_vt))
-#endif
- && type_size(&func_vt,&align) > 4)
+ if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&
+ !gfunc_sret(&func_vt, func_var, &ret_type, &align))
{
n++;
struct_ret = 1;
@@ -1244,7 +1242,7 @@ void gfunc_prolog(CType *func_type)
for(sym2=sym->next;sym2 && (n<4 || nf<16);sym2=sym2->next) {
size = type_size(&sym2->type, &align);
#ifdef TCC_ARM_HARDFLOAT
- if (!variadic && (is_float(sym2->type.t)
+ if (!func_var && (is_float(sym2->type.t)
|| is_hgen_float_aggr(&sym2->type))) {
int tmpnf = assign_vfpreg(&avregs, align, size);
tmpnf += (size + 3) / 4;
@@ -1255,9 +1253,9 @@ void gfunc_prolog(CType *func_type)
n += (size + 3) / 4;
}
o(0xE1A0C00D); /* mov ip,sp */
- if(variadic)
+ if (func_var)
n=4;
- if(n) {
+ if (n) {
if(n>4)
n=4;
#ifdef TCC_ARM_EABI
@@ -1289,7 +1287,7 @@ void gfunc_prolog(CType *func_type)
size = (size + 3) >> 2;
align = (align + 3) & ~3;
#ifdef TCC_ARM_HARDFLOAT
- if (!variadic && (is_float(sym->type.t)
+ if (!func_var && (is_float(sym->type.t)
|| is_hgen_float_aggr(&sym->type))) {
int fpn = assign_vfpreg(&avregs, align, size << 2);
if (fpn >= 0) {
@@ -1329,10 +1327,14 @@ void gfunc_epilog(void)
{
uint32_t x;
int diff;
+ /* Copy float return value to core register if base standard is used and
+ float computation is made with VFP */
#ifdef TCC_ARM_EABI
- /* Useless but harmless copy of the float result into main register(s) in case
- of variadic function in the hardfloat variant */
- if(is_float(func_vt.t)) {
+ if (
+#ifdef TCC_ARM_HARDFLOAT
+ func_var &&
+#endif
+ is_float(func_vt.t)) {
if((func_vt.t & VT_BTYPE) == VT_FLOAT)
o(0xEE100A10); /* fmrs r0, s0 */
else {
diff --git a/c67-gen.c b/c67-gen.c
index df4b5d3..f2baea5 100644
--- a/c67-gen.c
+++ b/c67-gen.c
@@ -1881,7 +1881,7 @@ static void gcall_or_jmp(int is_jmp)
/* Return the number of registers needed to return the struct, or 0 if
returning via struct pointer. */
-ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align) {
*ret_align = 1; // Never have to re-align return values for x86-64
return 0;
}
@@ -1971,6 +1971,7 @@ void gfunc_prolog(CType * func_type)
/* if the function returns a structure, then add an
implicit pointer parameter */
func_vt = sym->type;
+ func_var = (sym->c == FUNC_ELLIPSIS);
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
func_vc = addr;
addr += 4;
diff --git a/i386-gen.c b/i386-gen.c
index 4201ac2..2eb6922 100644
--- a/i386-gen.c
+++ b/i386-gen.c
@@ -376,7 +376,7 @@ static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
/* Return the number of registers needed to return the struct, or 0 if
returning via struct pointer. */
-ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align)
+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align)
{
#ifdef TCC_TARGET_PE
int size, align;
@@ -527,6 +527,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
/* if the function returns a structure, then add an
implicit pointer parameter */
func_vt = sym->type;
+ func_var = (sym->c == FUNC_ELLIPSIS);
#ifdef TCC_TARGET_PE
size = type_size(&func_vt,&align);
if (((func_vt.t & VT_BTYPE) == VT_STRUCT) && (size > 8)) {
diff --git a/il-gen.c b/il-gen.c
index 33f9f36..9e1ec64 100644
--- a/il-gen.c
+++ b/il-gen.c
@@ -441,6 +441,7 @@ void gfunc_prolog(int t)
/* if the function returns a structure, then add an
implicit pointer parameter */
func_vt = sym->t;
+ func_var = (sym->c == FUNC_ELLIPSIS);
if ((func_vt & VT_BTYPE) == VT_STRUCT) {
func_vc = addr;
addr++;
diff --git a/tcc.h b/tcc.h
index 50642b7..21957e7 100644
--- a/tcc.h
+++ b/tcc.h
@@ -1176,6 +1176,7 @@ ST_DATA int const_wanted; /* true if constant wanted */
ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */
ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */
ST_DATA CType func_vt; /* current function return type (used by return instruction) */
+ST_DATA int func_var; /* true if current function is variadic */
ST_DATA int func_vc;
ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */
ST_DATA char *funcname;
@@ -1288,7 +1289,7 @@ ST_FUNC void gsym_addr(int t, int a);
ST_FUNC void gsym(int t);
ST_FUNC void load(int r, SValue *sv);
ST_FUNC void store(int r, SValue *v);
-ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *align);
+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align);
ST_FUNC void gfunc_call(int nb_args);
ST_FUNC void gfunc_prolog(CType *func_type);
ST_FUNC void gfunc_epilog(void);
diff --git a/tccgen.c b/tccgen.c
index 55b03e6..8355aae 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -66,6 +66,7 @@ ST_DATA int const_wanted; /* true if constant wanted */
ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */
ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */
ST_DATA CType func_vt; /* current function return type (used by return instruction) */
+ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */
ST_DATA int func_vc;
ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */
ST_DATA char *funcname;
@@ -3960,7 +3961,7 @@ ST_FUNC void unary(void)
} else if (tok == '(') {
SValue ret;
Sym *sa;
- int nb_args, ret_nregs, ret_align;
+ int nb_args, ret_nregs, ret_align, variadic;
/* function call */
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
@@ -3984,7 +3985,9 @@ ST_FUNC void unary(void)
ret.r2 = VT_CONST;
/* compute first implicit argument if a structure is returned */
if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
- ret_nregs = gfunc_sret(&s->type, &ret.type, &ret_align);
+ variadic = (s->c == FUNC_ELLIPSIS);
+ ret_nregs = gfunc_sret(&s->type, variadic, &ret.type,
+ &ret_align);
if (!ret_nregs) {
/* get some space for the returned structure */
size = type_size(&s->type, &align);
@@ -4637,7 +4640,8 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
CType type, ret_type;
int ret_align, ret_nregs;
- ret_nregs = gfunc_sret(&func_vt, &ret_type, &ret_align);
+ ret_nregs = gfunc_sret(&func_vt, func_var, &ret_type,
+ &ret_align);
if (0 == ret_nregs) {
/* if returning structure, must copy it to implicit
first pointer arg location */
@@ -5747,6 +5751,7 @@ static void gen_function(Sym *sym)
cur_text_section = NULL;
funcname = ""; /* for safety */
func_vt.t = VT_VOID; /* for safety */
+ func_var = 0; /* for safety */
ind = 0; /* for safety */
nocode_wanted = saved_nocode_wanted;
}
diff --git a/x86_64-gen.c b/x86_64-gen.c
index fe028d9..9aee875 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -658,7 +658,7 @@ void gen_offs_sp(int b, int r, int d)
/* Return the number of registers needed to return the struct, or 0 if
returning via struct pointer. */
-ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align)
+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align)
{
int size, align;
*ret_align = 1; // Never have to re-align return values for x86-64
@@ -833,6 +833,7 @@ void gfunc_prolog(CType *func_type)
/* if the function returns a structure, then add an
implicit pointer parameter */
func_vt = sym->type;
+ func_var = (sym->c == FUNC_ELLIPSIS);
size = gfunc_arg_size(&func_vt);
if (size > 8) {
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);