Tests in abitest.c now work on Win32.

I expect that Linux-x86 is probably fine. All other architectures
except ARM are definitely broken since I haven't yet implemented
gfunc_sret for these, although replicating the current behaviour
should be straightforward.
This commit is contained in:
James Lyon 2013-04-18 17:27:34 +01:00
parent ce5e12c2f9
commit 2bbfaf436f
7 changed files with 173 additions and 66 deletions

View File

@ -45,7 +45,13 @@ endif
# make libtcc as static or dynamic library?
ifdef DISABLE_STATIC
ifndef CONFIG_WIN32
LIBTCC=libtcc.so.1.0
else
LIBTCC=libtcc.dll
LIBTCC_DLL=yes
LIBTCC_EXTRA=libtcc.def libtcc.a
endif
LINK_LIBTCC=-Wl,-rpath,"$(libdir)"
ifdef DISABLE_RPATH
LINK_LIBTCC=
@ -126,7 +132,7 @@ ifdef CONFIG_USE_LIBGCC
LIBTCC1=
endif
TCCLIBS = $(LIBTCC1) $(LIBTCC)
TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCC_EXTRA)
TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
ifdef CONFIG_CROSS
@ -185,14 +191,21 @@ endif
$(LIBTCC_OBJ) tcc.o : %.o : %.c $(LIBTCC_INC)
$(CC) -o $@ -c $< $(NATIVE_DEFINES) $(CPPFLAGS) $(CFLAGS)
ifndef LIBTCC_DLL
libtcc.a: $(LIBTCC_OBJ)
$(AR) rcs $@ $^
endif
libtcc.so.1.0: $(LIBTCC_OBJ)
$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
libtcc.so.1.0: CFLAGS+=-fPIC
ifdef LIBTCC_DLL
libtcc.dll libtcc.def libtcc.a: $(LIBTCC_OBJ)
$(CC) -shared $^ -o $@ $(LDFLAGS) -Wl,--output-def,libtcc.def,--out-implib,libtcc.a
endif
# windows utilities
tiny_impdef$(EXESUF): win32/tools/tiny_impdef.c
$(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
@ -286,7 +299,8 @@ install: $(PROGS) $(TCCLIBS) $(TCCDOCS)
cp -r $(top_srcdir)/win32/examples/. "$(tccdir)/examples"
$(INSTALL) -m644 $(addprefix $(top_srcdir)/include/,$(TCC_INCLUDES)) "$(tccdir)/include"
$(INSTALL) -m644 tcc-doc.html $(top_srcdir)/win32/tcc-win32.txt "$(tccdir)/doc"
$(INSTALL) -m644 $(LIBTCC) $(top_srcdir)/libtcc.h "$(tccdir)/libtcc"
$(INSTALL) -m644 $(top_srcdir)/libtcc.h $(LIBTCC_EXTRA) "$(tccdir)/libtcc"
$(INSTALL) -m644 $(LIBTCC) $(tccdir)
ifdef CONFIG_CROSS
mkdir -p "$(tccdir)/lib/32"
mkdir -p "$(tccdir)/lib/64"

View File

@ -800,6 +800,19 @@ int assign_fpreg(struct avail_regs *avregs, int align, int size)
}
#endif
/* Return 1 if this function returns via an sret pointer, 0 otherwise */
ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *align) {
size = type_size(vt, &align);
if (size > 4) {
return 1;
} else {
*align = 4;
ret->ref = NULL;
ret->t = VT_INT;
}
return 0;
}
/* Generate function call. The function address is pushed first, then
all the parameters in call order. This functions pops all the
parameters and the function address. */

View File

@ -364,6 +364,28 @@ static void gcall_or_jmp(int is_jmp)
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
/* Return 1 if this function returns via an sret pointer, 0 otherwise */
ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
*ret_align = 1; // Never have to re-align return values for x86
#ifdef TCC_TARGET_PE
int size, align;
size = type_size(vt, &align);
if (size > 8) {
return 1;
} else if (size > 4) {
ret->ref = NULL;
ret->t = VT_LLONG;
return 0;
} else {
ret->ref = NULL;
ret->t = VT_INT;
return 0;
}
#else
return 1;
#endif
}
/* Generate function call. The function address is pushed first, then
all the parameters in call order. This functions pops all the
parameters and the function address. */
@ -444,10 +466,6 @@ ST_FUNC void gfunc_call(int nb_args)
}
gcall_or_jmp(0);
#ifdef TCC_TARGET_PE
if ((func_sym->type.t & VT_BTYPE) == VT_STRUCT)
args_size -= 4;
#endif
if (args_size && func_call != FUNC_STDCALL)
gadd_sp(args_size);
vtop--;
@ -491,7 +509,12 @@ ST_FUNC void gfunc_prolog(CType *func_type)
/* if the function returns a structure, then add an
implicit pointer parameter */
func_vt = sym->type;
#ifdef TCC_TARGET_PE
size = type_size(&func_vt,&align);
if (((func_vt.t & VT_BTYPE) == VT_STRUCT) && (size > 8)) {
#else
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
#endif
/* XXX: fastcall case ? */
func_vc = addr;
addr += 4;
@ -526,10 +549,6 @@ ST_FUNC void gfunc_prolog(CType *func_type)
/* pascal type call ? */
if (func_call == FUNC_STDCALL)
func_ret_sub = addr - 8;
#ifdef TCC_TARGET_PE
else if (func_vc)
func_ret_sub = 4;
#endif
#ifdef CONFIG_TCC_BCHECK
/* leave some room for bound checking code */

1
tcc.h
View File

@ -1267,6 +1267,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 void gfunc_call(int nb_args);
ST_FUNC void gfunc_prolog(CType *func_type);
ST_FUNC void gfunc_epilog(void);

View File

@ -3850,7 +3850,7 @@ ST_FUNC void unary(void)
} else if (tok == '(') {
SValue ret;
Sym *sa;
int nb_args;
int nb_args, sret;
/* function call */
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
@ -3874,18 +3874,26 @@ 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) {
/* get some space for the returned structure */
size = type_size(&s->type, &align);
loc = (loc - size) & -align;
ret.type = s->type;
ret.r = VT_LOCAL | VT_LVAL;
/* pass it as 'int' to avoid structure arg passing
problems */
vseti(VT_LOCAL, loc);
ret.c = vtop->c;
nb_args++;
int ret_align;
sret = gfunc_sret(&s->type, &ret.type, &ret_align);
if (sret) {
/* get some space for the returned structure */
size = type_size(&s->type, &align);
loc = (loc - size) & -align;
ret.type = s->type;
ret.r = VT_LOCAL | VT_LVAL;
/* pass it as 'int' to avoid structure arg passing
problems */
vseti(VT_LOCAL, loc);
ret.c = vtop->c;
nb_args++;
}
} else {
ret.type = s->type;
sret = 0;
ret.type = s->type;
}
if (!sret) {
/* return in register */
if (is_float(ret.type.t)) {
ret.r = reg_fret(ret.type.t);
@ -3919,6 +3927,17 @@ ST_FUNC void unary(void)
/* return value */
vsetc(&ret.type, ret.r, &ret.c);
vtop->r2 = ret.r2;
/* handle packed struct return */
if (((s->type.t & VT_BTYPE) == VT_STRUCT) && !sret) {
size = type_size(&s->type, &align);
loc = (loc - size) & -align;
int addr = loc;
vset(&ret.type, VT_LOCAL | VT_LVAL, addr);
vswap();
vstore();
vtop--;
vset(&s->type, VT_LOCAL | VT_LVAL, addr);
}
} else {
break;
}
@ -4466,40 +4485,38 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
gexpr();
gen_assign_cast(&func_vt);
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
CType type;
/* if returning structure, must copy it to implicit
first pointer arg location */
#ifdef TCC_ARM_EABI
int align, size;
size = type_size(&func_vt,&align);
if(size <= 4)
{
if((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & 3))
&& (align & 3))
{
int addr;
loc = (loc - size) & -4;
CType type, ret_type;
int ret_align;
if (gfunc_sret(&func_vt, &ret_type, &ret_align)) {
/* if returning structure, must copy it to implicit
first pointer arg location */
type = func_vt;
mk_pointer(&type);
vset(&type, VT_LOCAL | VT_LVAL, func_vc);
indir();
vswap();
/* copy structure value to pointer */
vstore();
} else {
/* returning structure packed into registers */
int size, addr, align;
size = type_size(&func_vt,&align);
if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))
&& (align & (ret_align-1))) {
loc = (loc - size) & -align;
addr = loc;
type = func_vt;
vset(&type, VT_LOCAL | VT_LVAL, addr);
vswap();
vstore();
vset(&int_type, VT_LOCAL | VT_LVAL, addr);
vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
}
vtop->type = int_type;
gv(RC_IRET);
} else {
#endif
type = func_vt;
mk_pointer(&type);
vset(&type, VT_LOCAL | VT_LVAL, func_vc);
indir();
vswap();
/* copy structure value to pointer */
vstore();
#ifdef TCC_ARM_EABI
vtop->type = ret_type;
if (is_float(ret_type.t))
gv(rc_fret(ret_type.t));
else
gv(RC_IRET);
}
#endif
} else if (is_float(func_vt.t)) {
gv(rc_fret(func_vt.t));
} else {

View File

@ -13,7 +13,7 @@ TESTS = \
hello-run \
libtest \
test3 \
abitest-exe \
abitest \
moretests
# test4 -- problem with -static
@ -180,12 +180,16 @@ asmtest: asmtest.ref
# Check that code generated by libtcc is binary compatible with
# that generated by CC
abitest$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC)
$(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir) -g -O0
abitest-cc$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC)
$(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir)
abitest-exe: abitest$(EXESUF)
abitest-tcc$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC)
$(TCC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir)
abitest: abitest-cc$(EXESUF) abitest-tcc$(EXESUF)
@echo ------------ $@ ------------
abitest$(EXESUF) lib_path=..
abitest-cc$(EXESUF) lib_path=..
abitest-tcc$(EXESUF) lib_path=..
# targets for development
%.bin: %.c tcc

View File

@ -37,24 +37,62 @@ static int run_callback(const char *src, callback_type callback) {
return result;
}
typedef struct test1_type_s {int x, y;} test1_type;
typedef test1_type (*test1_function_type) ();
/*
* reg_pack_test: return a small struct which should be packed into
* registers (Win32) during return.
*/
typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;
typedef reg_pack_test_type (*reg_pack_test_function_type) (reg_pack_test_type);
static int test1_callback(void *ptr) {
test1_type r;
r = ((test1_function_type)ptr)();
return ((r.x == 10) && (r.y == 35)) ? 0 : -1;
static int reg_pack_test_callback(void *ptr) {
reg_pack_test_function_type f = (reg_pack_test_function_type)ptr;
reg_pack_test_type a = {10, 35};
reg_pack_test_type r;
r = f(a);
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
}
static int test1() {
static int reg_pack_test(void) {
const char *src =
"typedef struct test1_type_s {int x, y;} test1_type;"
"test1_type f() {\n"
" test1_type r = {10, 35};\n"
"typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;"
"reg_pack_test_type f(reg_pack_test_type a) {\n"
" reg_pack_test_type r = {a.x*5, a.y*3};\n"
" return r;\n"
"}\n";
return run_callback(src, test1_callback);
return run_callback(src, reg_pack_test_callback);
}
/*
* sret_test: Create a struct large enough to be returned via sret
* (hidden pointer as first function argument)
*/
typedef struct sret_test_type_s {
long long a;
long long b;
} sret_test_type;
typedef sret_test_type (*sret_test_function_type) (sret_test_type);
static int sret_test_callback(void *ptr) {
sret_test_function_type f = (sret_test_function_type)(ptr);
sret_test_type x = {5436LL, 658277698LL};
sret_test_type r = f(x);
return ((r.a==x.a*35)&&(r.b==x.b*19)) ? 0 : -1;
}
static int sret_test(void) {
const char *src =
"typedef struct sret_test_type_s {\n"
" long long a;\n"
" long long b;\n"
"} sret_test_type;\n"
"sret_test_type f(sret_test_type x) {\n"
" sret_test_type r = {x.a*35, x.b*19};\n"
" return r;\n"
"}\n";
return run_callback(src, sret_test_callback);
}
#define RUN_TEST(t) \
@ -75,6 +113,7 @@ int main(int argc, char **argv) {
if (argc == 2 && !memcmp(argv[1], "lib_path=",9))
tccdir = argv[1] + 9;
RUN_TEST(test1);
RUN_TEST(reg_pack_test);
RUN_TEST(sret_test);
return retval;
}