History

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.

James Lyon committed 13 years ago

Commit 2bbfaf41 parent ce5e12c7 files · +173 −66Browse files

Unified · Split

7 files
  1. Makefile +16 −2
  2. arm-gen.c +13 −0
  3. i386-gen.c +27 −8
  4. tcc.h +1 −0
  5. tccgen.c +56 −39
  6. tests/Makefile +9 −5
  7. tests/abitest.c +51 −12
Makefile+16−2
@@ -45,7 +45,13 @@ endif · 44 unmodified lines
4545
4646 # make libtcc as static or dynamic library?
4747 ifdef DISABLE_STATIC
48+ifndef CONFIG_WIN32
4849 LIBTCC=libtcc.so.1.0
50+else
51+LIBTCC=libtcc.dll
52+LIBTCC_DLL=yes
53+LIBTCC_EXTRA=libtcc.def libtcc.a
54+endif
4955 LINK_LIBTCC=-Wl,-rpath,"$(libdir)"
5056 ifdef DISABLE_RPATH
5157 LINK_LIBTCC=
@@ -126,7 +132,7 @@ ifdef CONFIG_USE_LIBGCC · 74 unmodified lines
126132 LIBTCC1=
127133 endif
128134
129−TCCLIBS = $(LIBTCC1) $(LIBTCC)
135+TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCC_EXTRA)
130136 TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
131137
132138 ifdef CONFIG_CROSS
@@ -185,14 +191,21 @@ endif · 52 unmodified lines
185191 $(LIBTCC_OBJ) tcc.o : %.o : %.c $(LIBTCC_INC)
186192 $(CC) -o $@ -c $< $(NATIVE_DEFINES) $(CPPFLAGS) $(CFLAGS)
187193
194+ifndef LIBTCC_DLL
188195 libtcc.a: $(LIBTCC_OBJ)
189196 $(AR) rcs $@ $^
197+endif
190198
191199 libtcc.so.1.0: $(LIBTCC_OBJ)
192200 $(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
193201
194202 libtcc.so.1.0: CFLAGS+=-fPIC
195203
204+ifdef LIBTCC_DLL
205+libtcc.dll libtcc.def libtcc.a: $(LIBTCC_OBJ)
206+ $(CC) -shared $^ -o $@ $(LDFLAGS) -Wl,--output-def,libtcc.def,--out-implib,libtcc.a
207+endif
208+
196209 # windows utilities
197210 tiny_impdef$(EXESUF): win32/tools/tiny_impdef.c
198211 $(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
@@ -286,7 +299,8 @@ install: $(PROGS) $(TCCLIBS) $(TCCDOCS) · 87 unmodified lines
286299 cp -r $(top_srcdir)/win32/examples/. "$(tccdir)/examples"
287300 $(INSTALL) -m644 $(addprefix $(top_srcdir)/include/,$(TCC_INCLUDES)) "$(tccdir)/include"
288301 $(INSTALL) -m644 tcc-doc.html $(top_srcdir)/win32/tcc-win32.txt "$(tccdir)/doc"
289− $(INSTALL) -m644 $(LIBTCC) $(top_srcdir)/libtcc.h "$(tccdir)/libtcc"
302+ $(INSTALL) -m644 $(top_srcdir)/libtcc.h $(LIBTCC_EXTRA) "$(tccdir)/libtcc"
303+ $(INSTALL) -m644 $(LIBTCC) $(tccdir)
290304 ifdef CONFIG_CROSS
291305 mkdir -p "$(tccdir)/lib/32"
292306 mkdir -p "$(tccdir)/lib/64"
arm-gen.c+13−0
@@ -800,6 +800,19 @@ int assign_fpreg(struct avail_regs *avregs, int align, int size) · 799 unmodified lines
800800 }
801801 #endif
802802
803+/* Return 1 if this function returns via an sret pointer, 0 otherwise */
804+ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *align) {
805+ size = type_size(vt, &align);
806+ if (size > 4) {
807+ return 1;
808+ } else {
809+ *align = 4;
810+ ret->ref = NULL;
811+ ret->t = VT_INT;
812+ }
813+ return 0;
814+}
815+
803816 /* Generate function call. The function address is pushed first, then
804817 all the parameters in call order. This functions pops all the
805818 parameters and the function address. */
i386-gen.c+27−8
@@ -364,6 +364,28 @@ static void gcall_or_jmp(int is_jmp) · 363 unmodified lines
364364 static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
365365 static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
366366
367+/* Return 1 if this function returns via an sret pointer, 0 otherwise */
368+ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
369+ *ret_align = 1; // Never have to re-align return values for x86
370+#ifdef TCC_TARGET_PE
371+ int size, align;
372+ size = type_size(vt, &align);
373+ if (size > 8) {
374+ return 1;
375+ } else if (size > 4) {
376+ ret->ref = NULL;
377+ ret->t = VT_LLONG;
378+ return 0;
379+ } else {
380+ ret->ref = NULL;
381+ ret->t = VT_INT;
382+ return 0;
383+ }
384+#else
385+ return 1;
386+#endif
387+}
388+
367389 /* Generate function call. The function address is pushed first, then
368390 all the parameters in call order. This functions pops all the
369391 parameters and the function address. */
@@ -444,10 +466,6 @@ ST_FUNC void gfunc_call(int nb_args) · 74 unmodified lines
444466 }
445467 gcall_or_jmp(0);
446468
447−#ifdef TCC_TARGET_PE
448− if ((func_sym->type.t & VT_BTYPE) == VT_STRUCT)
449− args_size -= 4;
450−#endif
451469 if (args_size && func_call != FUNC_STDCALL)
452470 gadd_sp(args_size);
453471 vtop--;
@@ -491,7 +509,12 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 37 unmodified lines
491509 /* if the function returns a structure, then add an
492510 implicit pointer parameter */
493511 func_vt = sym->type;
512+#ifdef TCC_TARGET_PE
513+ size = type_size(&func_vt,&align);
514+ if (((func_vt.t & VT_BTYPE) == VT_STRUCT) && (size > 8)) {
515+#else
494516 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
517+#endif
495518 /* XXX: fastcall case ? */
496519 func_vc = addr;
497520 addr += 4;
@@ -526,10 +549,6 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 28 unmodified lines
526549 /* pascal type call ? */
527550 if (func_call == FUNC_STDCALL)
528551 func_ret_sub = addr - 8;
529−#ifdef TCC_TARGET_PE
530− else if (func_vc)
531− func_ret_sub = 4;
532−#endif
533552
534553 #ifdef CONFIG_TCC_BCHECK
535554 /* leave some room for bound checking code */
tcc.h+1−0
@@ -1267,6 +1267,7 @@ ST_FUNC void gsym_addr(int t, int a); · 1266 unmodified lines
12671267 ST_FUNC void gsym(int t);
12681268 ST_FUNC void load(int r, SValue *sv);
12691269 ST_FUNC void store(int r, SValue *v);
1270+ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *align);
12701271 ST_FUNC void gfunc_call(int nb_args);
12711272 ST_FUNC void gfunc_prolog(CType *func_type);
12721273 ST_FUNC void gfunc_epilog(void);
tccgen.c+56−39
@@ -3850,7 +3850,7 @@ ST_FUNC void unary(void) · 3849 unmodified lines
38503850 } else if (tok == '(') {
38513851 SValue ret;
38523852 Sym *sa;
3853− int nb_args;
3853+ int nb_args, sret;
38543854
38553855 /* function call */
38563856 if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
@@ -3874,18 +3874,26 @@ ST_FUNC void unary(void) · 17 unmodified lines
38743874 ret.r2 = VT_CONST;
38753875 /* compute first implicit argument if a structure is returned */
38763876 if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
3877− /* get some space for the returned structure */
3878− size = type_size(&s->type, &align);
3879− loc = (loc - size) & -align;
3880− ret.type = s->type;
3881− ret.r = VT_LOCAL | VT_LVAL;
3882− /* pass it as 'int' to avoid structure arg passing
3883− problems */
3884− vseti(VT_LOCAL, loc);
3885− ret.c = vtop->c;
3886− nb_args++;
3877+ int ret_align;
3878+ sret = gfunc_sret(&s->type, &ret.type, &ret_align);
3879+ if (sret) {
3880+ /* get some space for the returned structure */
3881+ size = type_size(&s->type, &align);
3882+ loc = (loc - size) & -align;
3883+ ret.type = s->type;
3884+ ret.r = VT_LOCAL | VT_LVAL;
3885+ /* pass it as 'int' to avoid structure arg passing
3886+ problems */
3887+ vseti(VT_LOCAL, loc);
3888+ ret.c = vtop->c;
3889+ nb_args++;
3890+ }
38873891 } else {
3888− ret.type = s->type;
3892+ sret = 0;
3893+ ret.type = s->type;
3894+ }
3895+
3896+ if (!sret) {
38893897 /* return in register */
38903898 if (is_float(ret.type.t)) {
38913899 ret.r = reg_fret(ret.type.t);
@@ -3919,6 +3927,17 @@ ST_FUNC void unary(void) · 27 unmodified lines
39193927 /* return value */
39203928 vsetc(&ret.type, ret.r, &ret.c);
39213929 vtop->r2 = ret.r2;
3930+ /* handle packed struct return */
3931+ if (((s->type.t & VT_BTYPE) == VT_STRUCT) && !sret) {
3932+ size = type_size(&s->type, &align);
3933+ loc = (loc - size) & -align;
3934+ int addr = loc;
3935+ vset(&ret.type, VT_LOCAL | VT_LVAL, addr);
3936+ vswap();
3937+ vstore();
3938+ vtop--;
3939+ vset(&s->type, VT_LOCAL | VT_LVAL, addr);
3940+ }
39223941 } else {
39233942 break;
39243943 }
@@ -4466,40 +4485,38 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 541 unmodified lines
44664485 gexpr();
44674486 gen_assign_cast(&func_vt);
44684487 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
4469− CType type;
4470− /* if returning structure, must copy it to implicit
4471− first pointer arg location */
4472−#ifdef TCC_ARM_EABI
4473− int align, size;
4474− size = type_size(&func_vt,&align);
4475− if(size <= 4)
4476− {
4477− if((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & 3))
4478− && (align & 3))
4479− {
4480− int addr;
4481− loc = (loc - size) & -4;
4488+ CType type, ret_type;
4489+ int ret_align;
4490+ if (gfunc_sret(&func_vt, &ret_type, &ret_align)) {
4491+ /* if returning structure, must copy it to implicit
4492+ first pointer arg location */
4493+ type = func_vt;
4494+ mk_pointer(&type);
4495+ vset(&type, VT_LOCAL | VT_LVAL, func_vc);
4496+ indir();
4497+ vswap();
4498+ /* copy structure value to pointer */
4499+ vstore();
4500+ } else {
4501+ /* returning structure packed into registers */
4502+ int size, addr, align;
4503+ size = type_size(&func_vt,&align);
4504+ if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))
4505+ && (align & (ret_align-1))) {
4506+ loc = (loc - size) & -align;
44824507 addr = loc;
44834508 type = func_vt;
44844509 vset(&type, VT_LOCAL | VT_LVAL, addr);
44854510 vswap();
44864511 vstore();
4487− vset(&int_type, VT_LOCAL | VT_LVAL, addr);
4512+ vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
44884513 }
4489− vtop->type = int_type;
4490− gv(RC_IRET);
4491− } else {
4492−#endif
4493− type = func_vt;
4494− mk_pointer(&type);
4495− vset(&type, VT_LOCAL | VT_LVAL, func_vc);
4496− indir();
4497− vswap();
4498− /* copy structure value to pointer */
4499− vstore();
4500−#ifdef TCC_ARM_EABI
4514+ vtop->type = ret_type;
4515+ if (is_float(ret_type.t))
4516+ gv(rc_fret(ret_type.t));
4517+ else
4518+ gv(RC_IRET);
45014519 }
4502−#endif
45034520 } else if (is_float(func_vt.t)) {
45044521 gv(rc_fret(func_vt.t));
45054522 } else {
tests/Makefile+9−5
@@ -13,7 +13,7 @@ TESTS = \ · 12 unmodified lines
1313 hello-run \
1414 libtest \
1515 test3 \
16− abitest-exe \
16+ abitest \
1717 moretests
1818
1919 # test4 -- problem with -static
@@ -180,12 +180,16 @@ asmtest: asmtest.ref · 160 unmodified lines
180180
181181 # Check that code generated by libtcc is binary compatible with
182182 # that generated by CC
183−abitest$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC)
184− $(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir) -g -O0
183+abitest-cc$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC)
184+ $(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir)
185+
186+abitest-tcc$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC)
187+ $(TCC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir)
185188
186−abitest-exe: abitest$(EXESUF)
189+abitest: abitest-cc$(EXESUF) abitest-tcc$(EXESUF)
187190 @echo ------------ $@ ------------
188− abitest$(EXESUF) lib_path=..
191+ abitest-cc$(EXESUF) lib_path=..
192+ abitest-tcc$(EXESUF) lib_path=..
189193
190194 # targets for development
191195 %.bin: %.c tcc
tests/abitest.c+51−12
@@ -37,24 +37,62 @@ static int run_callback(const char *src, callback_type callback) { · 36 unmodified lines
3737 return result;
3838 }
3939
40−typedef struct test1_type_s {int x, y;} test1_type;
41−typedef test1_type (*test1_function_type) ();
40+/*
41+ * reg_pack_test: return a small struct which should be packed into
42+ * registers (Win32) during return.
43+ */
44+typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;
45+typedef reg_pack_test_type (*reg_pack_test_function_type) (reg_pack_test_type);
46+
47+static int reg_pack_test_callback(void *ptr) {
48+ reg_pack_test_function_type f = (reg_pack_test_function_type)ptr;
49+ reg_pack_test_type a = {10, 35};
50+ reg_pack_test_type r;
51+ r = f(a);
52+ return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
53+}
54+
55+static int reg_pack_test(void) {
56+ const char *src =
57+ "typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;"
58+ "reg_pack_test_type f(reg_pack_test_type a) {\n"
59+ " reg_pack_test_type r = {a.x*5, a.y*3};\n"
60+ " return r;\n"
61+ "}\n";
62+
63+ return run_callback(src, reg_pack_test_callback);
64+}
65+
66+/*
67+ * sret_test: Create a struct large enough to be returned via sret
68+ * (hidden pointer as first function argument)
69+ */
70+typedef struct sret_test_type_s {
71+ long long a;
72+ long long b;
73+} sret_test_type;
74+
75+typedef sret_test_type (*sret_test_function_type) (sret_test_type);
4276
43−static int test1_callback(void *ptr) {
44− test1_type r;
45− r = ((test1_function_type)ptr)();
46− return ((r.x == 10) && (r.y == 35)) ? 0 : -1;
77+static int sret_test_callback(void *ptr) {
78+ sret_test_function_type f = (sret_test_function_type)(ptr);
79+ sret_test_type x = {5436LL, 658277698LL};
80+ sret_test_type r = f(x);
81+ return ((r.a==x.a*35)&&(r.b==x.b*19)) ? 0 : -1;
4782 }
4883
49−static int test1() {
84+static int sret_test(void) {
5085 const char *src =
51− "typedef struct test1_type_s {int x, y;} test1_type;"
52− "test1_type f() {\n"
53− " test1_type r = {10, 35};\n"
86+ "typedef struct sret_test_type_s {\n"
87+ " long long a;\n"
88+ " long long b;\n"
89+ "} sret_test_type;\n"
90+ "sret_test_type f(sret_test_type x) {\n"
91+ " sret_test_type r = {x.a*35, x.b*19};\n"
5492 " return r;\n"
5593 "}\n";
5694
57− return run_callback(src, test1_callback);
95+ return run_callback(src, sret_test_callback);
5896 }
5997
6098 #define RUN_TEST(t) \
@@ -75,6 +113,7 @@ int main(int argc, char **argv) { · 14 unmodified lines
75113 if (argc == 2 && !memcmp(argv[1], "lib_path=",9))
76114 tccdir = argv[1] + 9;
77115
78− RUN_TEST(test1);
116+ RUN_TEST(reg_pack_test);
117+ RUN_TEST(sret_test);
79118 return retval;
80119 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t