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
45 45
46# make libtcc as static or dynamic library?46# make libtcc as static or dynamic library?
47ifdef DISABLE_STATIC47ifdef DISABLE_STATIC
48ifndef CONFIG_WIN32
48LIBTCC=libtcc.so.1.049LIBTCC=libtcc.so.1.0
50else
51LIBTCC=libtcc.dll
52LIBTCC_DLL=yes
53LIBTCC_EXTRA=libtcc.def libtcc.a
54endif
49LINK_LIBTCC=-Wl,-rpath,"$(libdir)"55LINK_LIBTCC=-Wl,-rpath,"$(libdir)"
50ifdef DISABLE_RPATH56ifdef DISABLE_RPATH
51LINK_LIBTCC=57LINK_LIBTCC=
@@ -126,7 +132,7 @@ ifdef CONFIG_USE_LIBGCC · 74 unmodified lines
126LIBTCC1=132LIBTCC1=
127endif133endif
128 134
129TCCLIBS = $(LIBTCC1) $(LIBTCC)135TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCC_EXTRA)
130TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info136TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
131 137
132ifdef CONFIG_CROSS138ifdef CONFIG_CROSS
@@ -185,14 +191,21 @@ endif · 52 unmodified lines
185$(LIBTCC_OBJ) tcc.o : %.o : %.c $(LIBTCC_INC)191$(LIBTCC_OBJ) tcc.o : %.o : %.c $(LIBTCC_INC)
186 $(CC) -o $@ -c $< $(NATIVE_DEFINES) $(CPPFLAGS) $(CFLAGS)192 $(CC) -o $@ -c $< $(NATIVE_DEFINES) $(CPPFLAGS) $(CFLAGS)
187 193
194ifndef LIBTCC_DLL
188libtcc.a: $(LIBTCC_OBJ)195libtcc.a: $(LIBTCC_OBJ)
189 $(AR) rcs $@ $^196 $(AR) rcs $@ $^
197endif
190 198
191libtcc.so.1.0: $(LIBTCC_OBJ)199libtcc.so.1.0: $(LIBTCC_OBJ)
192 $(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)200 $(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
193 201
194libtcc.so.1.0: CFLAGS+=-fPIC202libtcc.so.1.0: CFLAGS+=-fPIC
195 203
204ifdef LIBTCC_DLL
205libtcc.dll libtcc.def libtcc.a: $(LIBTCC_OBJ)
206 $(CC) -shared $^ -o $@ $(LDFLAGS) -Wl,--output-def,libtcc.def,--out-implib,libtcc.a
207endif
208
196# windows utilities209# windows utilities
197tiny_impdef$(EXESUF): win32/tools/tiny_impdef.c210tiny_impdef$(EXESUF): win32/tools/tiny_impdef.c
198 $(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)211 $(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
@@ -286,7 +299,8 @@ install: $(PROGS) $(TCCLIBS) $(TCCDOCS) · 87 unmodified lines
286 cp -r $(top_srcdir)/win32/examples/. "$(tccdir)/examples"299 cp -r $(top_srcdir)/win32/examples/. "$(tccdir)/examples"
287 $(INSTALL) -m644 $(addprefix $(top_srcdir)/include/,$(TCC_INCLUDES)) "$(tccdir)/include"300 $(INSTALL) -m644 $(addprefix $(top_srcdir)/include/,$(TCC_INCLUDES)) "$(tccdir)/include"
288 $(INSTALL) -m644 tcc-doc.html $(top_srcdir)/win32/tcc-win32.txt "$(tccdir)/doc"301 $(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)
290ifdef CONFIG_CROSS304ifdef CONFIG_CROSS
291 mkdir -p "$(tccdir)/lib/32"305 mkdir -p "$(tccdir)/lib/32"
292 mkdir -p "$(tccdir)/lib/64"306 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
800}800}
801#endif801#endif
802 802
803/* Return 1 if this function returns via an sret pointer, 0 otherwise */
804ST_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
803/* Generate function call. The function address is pushed first, then816/* Generate function call. The function address is pushed first, then
804 all the parameters in call order. This functions pops all the817 all the parameters in call order. This functions pops all the
805 parameters and the function address. */818 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
364static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };364static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
365static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };365static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
366 366
367/* Return 1 if this function returns via an sret pointer, 0 otherwise */
368ST_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
367/* Generate function call. The function address is pushed first, then389/* Generate function call. The function address is pushed first, then
368 all the parameters in call order. This functions pops all the390 all the parameters in call order. This functions pops all the
369 parameters and the function address. */391 parameters and the function address. */
@@ -444,10 +466,6 @@ ST_FUNC void gfunc_call(int nb_args) · 74 unmodified lines
444 }466 }
445 gcall_or_jmp(0);467 gcall_or_jmp(0);
446 468
447#ifdef TCC_TARGET_PE
448 if ((func_sym->type.t & VT_BTYPE) == VT_STRUCT)
449 args_size -= 4;
450#endif
451 if (args_size && func_call != FUNC_STDCALL)469 if (args_size && func_call != FUNC_STDCALL)
452 gadd_sp(args_size);470 gadd_sp(args_size);
453 vtop--;471 vtop--;
@@ -491,7 +509,12 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 37 unmodified lines
491 /* if the function returns a structure, then add an509 /* if the function returns a structure, then add an
492 implicit pointer parameter */510 implicit pointer parameter */
493 func_vt = sym->type;511 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
494 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {516 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
517#endif
495 /* XXX: fastcall case ? */518 /* XXX: fastcall case ? */
496 func_vc = addr;519 func_vc = addr;
497 addr += 4;520 addr += 4;
@@ -526,10 +549,6 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 28 unmodified lines
526 /* pascal type call ? */549 /* pascal type call ? */
527 if (func_call == FUNC_STDCALL)550 if (func_call == FUNC_STDCALL)
528 func_ret_sub = addr - 8;551 func_ret_sub = addr - 8;
529#ifdef TCC_TARGET_PE
530 else if (func_vc)
531 func_ret_sub = 4;
532#endif
533 552
534#ifdef CONFIG_TCC_BCHECK553#ifdef CONFIG_TCC_BCHECK
535 /* leave some room for bound checking code */554 /* 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
1267ST_FUNC void gsym(int t);1267ST_FUNC void gsym(int t);
1268ST_FUNC void load(int r, SValue *sv);1268ST_FUNC void load(int r, SValue *sv);
1269ST_FUNC void store(int r, SValue *v);1269ST_FUNC void store(int r, SValue *v);
1270ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *align);
1270ST_FUNC void gfunc_call(int nb_args);1271ST_FUNC void gfunc_call(int nb_args);
1271ST_FUNC void gfunc_prolog(CType *func_type);1272ST_FUNC void gfunc_prolog(CType *func_type);
1272ST_FUNC void gfunc_epilog(void);1273ST_FUNC void gfunc_epilog(void);
tccgen.c+56−39
@@ -3850,7 +3850,7 @@ ST_FUNC void unary(void) · 3849 unmodified lines
3850 } else if (tok == '(') {3850 } else if (tok == '(') {
3851 SValue ret;3851 SValue ret;
3852 Sym *sa;3852 Sym *sa;
3853 int nb_args;3853 int nb_args, sret;
3854 3854
3855 /* function call */3855 /* function call */
3856 if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {3856 if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
@@ -3874,18 +3874,26 @@ ST_FUNC void unary(void) · 17 unmodified lines
3874 ret.r2 = VT_CONST;3874 ret.r2 = VT_CONST;
3875 /* compute first implicit argument if a structure is returned */3875 /* compute first implicit argument if a structure is returned */
3876 if ((s->type.t & VT_BTYPE) == VT_STRUCT) {3876 if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
3877 /* get some space for the returned structure */3877 int ret_align;
3878 size = type_size(&s->type, &align);3878 sret = gfunc_sret(&s->type, &ret.type, &ret_align);
3879 loc = (loc - size) & -align;3879 if (sret) {
3880 ret.type = s->type;3880 /* get some space for the returned structure */
3881 ret.r = VT_LOCAL | VT_LVAL;3881 size = type_size(&s->type, &align);
3882 /* pass it as 'int' to avoid structure arg passing3882 loc = (loc - size) & -align;
3883 problems */3883 ret.type = s->type;
3884 vseti(VT_LOCAL, loc);3884 ret.r = VT_LOCAL | VT_LVAL;
3885 ret.c = vtop->c;3885 /* pass it as 'int' to avoid structure arg passing
3886 nb_args++;3886 problems */
3887 vseti(VT_LOCAL, loc);
3888 ret.c = vtop->c;
3889 nb_args++;
3890 }
3887 } else {3891 } else {
3888 ret.type = s->type; 3892 sret = 0;
3893 ret.type = s->type;
3894 }
3895
3896 if (!sret) {
3889 /* return in register */3897 /* return in register */
3890 if (is_float(ret.type.t)) {3898 if (is_float(ret.type.t)) {
3891 ret.r = reg_fret(ret.type.t);3899 ret.r = reg_fret(ret.type.t);
@@ -3919,6 +3927,17 @@ ST_FUNC void unary(void) · 27 unmodified lines
3919 /* return value */3927 /* return value */
3920 vsetc(&ret.type, ret.r, &ret.c);3928 vsetc(&ret.type, ret.r, &ret.c);
3921 vtop->r2 = ret.r2;3929 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 }
3922 } else {3941 } else {
3923 break;3942 break;
3924 }3943 }
@@ -4466,40 +4485,38 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 541 unmodified lines
4466 gexpr();4485 gexpr();
4467 gen_assign_cast(&func_vt);4486 gen_assign_cast(&func_vt);
4468 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {4487 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
4469 CType type;4488 CType type, ret_type;
4470 /* if returning structure, must copy it to implicit4489 int ret_align;
4471 first pointer arg location */4490 if (gfunc_sret(&func_vt, &ret_type, &ret_align)) {
4472#ifdef TCC_ARM_EABI4491 /* if returning structure, must copy it to implicit
4473 int align, size;4492 first pointer arg location */
4474 size = type_size(&func_vt,&align);4493 type = func_vt;
4475 if(size <= 4)4494 mk_pointer(&type);
4476 {4495 vset(&type, VT_LOCAL | VT_LVAL, func_vc);
4477 if((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & 3))4496 indir();
4478 && (align & 3))4497 vswap();
4479 {4498 /* copy structure value to pointer */
4480 int addr;4499 vstore();
4481 loc = (loc - size) & -4;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;
4482 addr = loc;4507 addr = loc;
4483 type = func_vt;4508 type = func_vt;
4484 vset(&type, VT_LOCAL | VT_LVAL, addr);4509 vset(&type, VT_LOCAL | VT_LVAL, addr);
4485 vswap();4510 vswap();
4486 vstore();4511 vstore();
4487 vset(&int_type, VT_LOCAL | VT_LVAL, addr);4512 vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
4488 }4513 }
4489 vtop->type = int_type;4514 vtop->type = ret_type;
4490 gv(RC_IRET);4515 if (is_float(ret_type.t))
4491 } else {4516 gv(rc_fret(ret_type.t));
4492#endif4517 else
4493 type = func_vt;4518 gv(RC_IRET);
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
4501 }4519 }
4502#endif
4503 } else if (is_float(func_vt.t)) {4520 } else if (is_float(func_vt.t)) {
4504 gv(rc_fret(func_vt.t));4521 gv(rc_fret(func_vt.t));
4505 } else {4522 } else {
tests/Makefile+9−5
@@ -13,7 +13,7 @@ TESTS = \ · 12 unmodified lines
13 hello-run \13 hello-run \
14 libtest \14 libtest \
15 test3 \15 test3 \
16 abitest-exe \16 abitest \
17 moretests17 moretests
18 18
19# test4 -- problem with -static19# test4 -- problem with -static
@@ -180,12 +180,16 @@ asmtest: asmtest.ref · 160 unmodified lines
180 180
181# Check that code generated by libtcc is binary compatible with181# Check that code generated by libtcc is binary compatible with
182# that generated by CC182# that generated by CC
183abitest$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC)183abitest-cc$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC)
184 $(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir) -g -O0184 $(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir)
185
186abitest-tcc$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC)
187 $(TCC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir)
185 188
186abitest-exe: abitest$(EXESUF)189abitest: abitest-cc$(EXESUF) abitest-tcc$(EXESUF)
187 @echo ------------ $@ ------------190 @echo ------------ $@ ------------
188 abitest$(EXESUF) lib_path=..191 abitest-cc$(EXESUF) lib_path=..
192 abitest-tcc$(EXESUF) lib_path=..
189 193
190# targets for development194# targets for development
191%.bin: %.c tcc195%.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
37 return result;37 return result;
38}38}
39 39
40typedef struct test1_type_s {int x, y;} test1_type;40/*
41typedef test1_type (*test1_function_type) ();41 * reg_pack_test: return a small struct which should be packed into
42 * registers (Win32) during return.
43 */
44typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;
45typedef reg_pack_test_type (*reg_pack_test_function_type) (reg_pack_test_type);
46
47static 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
55static 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 */
70typedef struct sret_test_type_s {
71 long long a;
72 long long b;
73} sret_test_type;
74
75typedef sret_test_type (*sret_test_function_type) (sret_test_type);
42 76
43static int test1_callback(void *ptr) {77static int sret_test_callback(void *ptr) {
44 test1_type r;78 sret_test_function_type f = (sret_test_function_type)(ptr);
45 r = ((test1_function_type)ptr)();79 sret_test_type x = {5436LL, 658277698LL};
46 return ((r.x == 10) && (r.y == 35)) ? 0 : -1;80 sret_test_type r = f(x);
81 return ((r.a==x.a*35)&&(r.b==x.b*19)) ? 0 : -1;
47}82}
48 83
49static int test1() {84static int sret_test(void) {
50 const char *src =85 const char *src =
51 "typedef struct test1_type_s {int x, y;} test1_type;"86 "typedef struct sret_test_type_s {\n"
52 "test1_type f() {\n"87 " long long a;\n"
53 " test1_type r = {10, 35};\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"
54 " return r;\n"92 " return r;\n"
55 "}\n";93 "}\n";
56 94
57 return run_callback(src, test1_callback);95 return run_callback(src, sret_test_callback);
58}96}
59 97
60#define RUN_TEST(t) \98#define RUN_TEST(t) \
@@ -75,6 +113,7 @@ int main(int argc, char **argv) { · 14 unmodified lines
75 if (argc == 2 && !memcmp(argv[1], "lib_path=",9))113 if (argc == 2 && !memcmp(argv[1], "lib_path=",9))
76 tccdir = argv[1] + 9;114 tccdir = argv[1] + 9;
77 115
78 RUN_TEST(test1);116 RUN_TEST(reg_pack_test);
117 RUN_TEST(sret_test);
79 return retval;118 return retval;
80}119}

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