aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Lyon <jamesly0n@hotmail.com>2013-04-18 17:27:34 +0100
committerJames Lyon <jamesly0n@hotmail.com>2013-04-18 17:27:34 +0100
commit2bbfaf436f937ace4809d84be812ea1ac7fd7352 (patch)
tree6e4f3f80611a8a471b5e84f42e05d2fd30f57e73
parentce5e12c2f950052d8109b6b7a56d900547705c08 (diff)
downloadtinycc-2bbfaf436f937ace4809d84be812ea1ac7fd7352.tar.gz
tinycc-2bbfaf436f937ace4809d84be812ea1ac7fd7352.tar.bz2
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.
-rw-r--r--Makefile18
-rw-r--r--arm-gen.c13
-rw-r--r--i386-gen.c35
-rw-r--r--tcc.h1
-rw-r--r--tccgen.c95
-rw-r--r--tests/Makefile14
-rw-r--r--tests/abitest.c63
7 files changed, 173 insertions, 66 deletions
diff --git a/Makefile b/Makefile
index fb94845..f487fbf 100644
--- a/Makefile
+++ b/Makefile
@@ -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"
diff --git a/arm-gen.c b/arm-gen.c
index 3e86d9e..03262aa 100644
--- a/arm-gen.c
+++ b/arm-gen.c
@@ -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. */
diff --git a/i386-gen.c b/i386-gen.c
index a9e1977..67123d6 100644
--- a/i386-gen.c
+++ b/i386-gen.c
@@ -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 */
diff --git a/tcc.h b/tcc.h
index ef645b1..f243ed0 100644
--- a/tcc.h
+++ b/tcc.h
@@ -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);
diff --git a/tccgen.c b/tccgen.c
index 0a6250c..febab11 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -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 {
diff --git a/tests/Makefile b/tests/Makefile
index f47ede4..ae5d47d 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -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-tcc$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC)
+ $(TCC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir)
-abitest-exe: abitest$(EXESUF)
+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
diff --git a/tests/abitest.c b/tests/abitest.c
index 51a30ba..90f4cb8 100644
--- a/tests/abitest.c
+++ b/tests/abitest.c
@@ -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 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 reg_pack_test(void) {
+ const char *src =
+ "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, 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 test1_callback(void *ptr) {
- test1_type r;
- r = ((test1_function_type)ptr)();
- return ((r.x == 10) && (r.y == 35)) ? 0 : -1;
+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 test1() {
+static int sret_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 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, test1_callback);
+ 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;
}