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.
Unified · Split
| @@ -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? |
| 47 | ifdef DISABLE_STATIC | 47 | ifdef DISABLE_STATIC |
| 48 | ifndef CONFIG_WIN32 | ||
| 48 | LIBTCC=libtcc.so.1.0 | 49 | LIBTCC=libtcc.so.1.0 |
| 50 | else | ||
| 51 | LIBTCC=libtcc.dll | ||
| 52 | LIBTCC_DLL=yes | ||
| 53 | LIBTCC_EXTRA=libtcc.def libtcc.a | ||
| 54 | endif | ||
| 49 | LINK_LIBTCC=-Wl,-rpath,"$(libdir)" | 55 | LINK_LIBTCC=-Wl,-rpath,"$(libdir)" |
| 50 | ifdef DISABLE_RPATH | 56 | ifdef DISABLE_RPATH |
| 51 | LINK_LIBTCC= | 57 | LINK_LIBTCC= |
| @@ -126,7 +132,7 @@ ifdef CONFIG_USE_LIBGCC · 74 unmodified lines | |||
| 126 | LIBTCC1= | 132 | LIBTCC1= |
| 127 | endif | 133 | endif |
| 128 | 134 | ||
| 129 | TCCLIBS = $(LIBTCC1) $(LIBTCC) | 135 | TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCC_EXTRA) |
| 130 | TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info | 136 | TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info |
| 131 | 137 | ||
| 132 | ifdef CONFIG_CROSS | 138 | ifdef 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 | ||
| 194 | ifndef LIBTCC_DLL | ||
| 188 | libtcc.a: $(LIBTCC_OBJ) | 195 | libtcc.a: $(LIBTCC_OBJ) |
| 189 | $(AR) rcs $@ $^ | 196 | $(AR) rcs $@ $^ |
| 197 | endif | ||
| 190 | 198 | ||
| 191 | libtcc.so.1.0: $(LIBTCC_OBJ) | 199 | libtcc.so.1.0: $(LIBTCC_OBJ) |
| 192 | $(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS) | 200 | $(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS) |
| 193 | 201 | ||
| 194 | libtcc.so.1.0: CFLAGS+=-fPIC | 202 | libtcc.so.1.0: CFLAGS+=-fPIC |
| 195 | 203 | ||
| 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 | |||
| 196 | # windows utilities | 209 | # windows utilities |
| 197 | tiny_impdef$(EXESUF): win32/tools/tiny_impdef.c | 210 | tiny_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) | ||
| 290 | ifdef CONFIG_CROSS | 304 | ifdef 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" |
| @@ -800,6 +800,19 @@ int assign_fpreg(struct avail_regs *avregs, int align, int size) · 799 unmodified lines | |||
| 800 | } | 800 | } |
| 801 | #endif | 801 | #endif |
| 802 | 802 | ||
| 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 | |||
| 803 | /* Generate function call. The function address is pushed first, then | 816 | /* Generate function call. The function address is pushed first, then |
| 804 | all the parameters in call order. This functions pops all the | 817 | all the parameters in call order. This functions pops all the |
| 805 | parameters and the function address. */ | 818 | parameters and the function address. */ |
| @@ -364,6 +364,28 @@ static void gcall_or_jmp(int is_jmp) · 363 unmodified lines | |||
| 364 | static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX }; | 364 | static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX }; |
| 365 | static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX }; | 365 | static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX }; |
| 366 | 366 | ||
| 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 | |||
| 367 | /* Generate function call. The function address is pushed first, then | 389 | /* Generate function call. The function address is pushed first, then |
| 368 | all the parameters in call order. This functions pops all the | 390 | 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 an | 509 | /* 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_BCHECK | 553 | #ifdef CONFIG_TCC_BCHECK |
| 535 | /* leave some room for bound checking code */ | 554 | /* leave some room for bound checking code */ |
| @@ -1267,6 +1267,7 @@ ST_FUNC void gsym_addr(int t, int a); · 1266 unmodified lines | |||
| 1267 | ST_FUNC void gsym(int t); | 1267 | ST_FUNC void gsym(int t); |
| 1268 | ST_FUNC void load(int r, SValue *sv); | 1268 | ST_FUNC void load(int r, SValue *sv); |
| 1269 | ST_FUNC void store(int r, SValue *v); | 1269 | ST_FUNC void store(int r, SValue *v); |
| 1270 | ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *align); | ||
| 1270 | ST_FUNC void gfunc_call(int nb_args); | 1271 | ST_FUNC void gfunc_call(int nb_args); |
| 1271 | ST_FUNC void gfunc_prolog(CType *func_type); | 1272 | ST_FUNC void gfunc_prolog(CType *func_type); |
| 1272 | ST_FUNC void gfunc_epilog(void); | 1273 | ST_FUNC void gfunc_epilog(void); |
| @@ -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 passing | 3882 | 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 implicit | 4489 | int ret_align; |
| 4471 | first pointer arg location */ | 4490 | if (gfunc_sret(&func_vt, &ret_type, &ret_align)) { |
| 4472 | #ifdef TCC_ARM_EABI | 4491 | /* 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 | #endif | 4517 | 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 { |
| @@ -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 | moretests | 17 | moretests |
| 18 | 18 | ||
| 19 | # test4 -- problem with -static | 19 | # 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 with | 181 | # Check that code generated by libtcc is binary compatible with |
| 182 | # that generated by CC | 182 | # that generated by CC |
| 183 | abitest$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC) | 183 | abitest-cc$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC) |
| 184 | $(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir) -g -O0 | 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) | ||
| 185 | 188 | ||
| 186 | abitest-exe: abitest$(EXESUF) | 189 | abitest: 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 development | 194 | # targets for development |
| 191 | %.bin: %.c tcc | 195 | %.bin: %.c tcc |
| @@ -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 | ||
| 40 | typedef struct test1_type_s {int x, y;} test1_type; | 40 | /* |
| 41 | typedef test1_type (*test1_function_type) (); | 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); | ||
| 42 | 76 | ||
| 43 | static int test1_callback(void *ptr) { | 77 | static 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 | ||
| 49 | static int test1() { | 84 | static 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 | } |