mirror of
https://github.com/mirror/tinycc.git
synced 2025-03-26 12:04:59 +08:00
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:
parent
ce5e12c2f9
commit
2bbfaf436f
18
Makefile
18
Makefile
@ -45,7 +45,13 @@ endif
|
|||||||
|
|
||||||
# make libtcc as static or dynamic library?
|
# make libtcc as static or dynamic library?
|
||||||
ifdef DISABLE_STATIC
|
ifdef DISABLE_STATIC
|
||||||
|
ifndef CONFIG_WIN32
|
||||||
LIBTCC=libtcc.so.1.0
|
LIBTCC=libtcc.so.1.0
|
||||||
|
else
|
||||||
|
LIBTCC=libtcc.dll
|
||||||
|
LIBTCC_DLL=yes
|
||||||
|
LIBTCC_EXTRA=libtcc.def libtcc.a
|
||||||
|
endif
|
||||||
LINK_LIBTCC=-Wl,-rpath,"$(libdir)"
|
LINK_LIBTCC=-Wl,-rpath,"$(libdir)"
|
||||||
ifdef DISABLE_RPATH
|
ifdef DISABLE_RPATH
|
||||||
LINK_LIBTCC=
|
LINK_LIBTCC=
|
||||||
@ -126,7 +132,7 @@ ifdef CONFIG_USE_LIBGCC
|
|||||||
LIBTCC1=
|
LIBTCC1=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
TCCLIBS = $(LIBTCC1) $(LIBTCC)
|
TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCC_EXTRA)
|
||||||
TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
|
TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
|
||||||
|
|
||||||
ifdef CONFIG_CROSS
|
ifdef CONFIG_CROSS
|
||||||
@ -185,14 +191,21 @@ endif
|
|||||||
$(LIBTCC_OBJ) tcc.o : %.o : %.c $(LIBTCC_INC)
|
$(LIBTCC_OBJ) tcc.o : %.o : %.c $(LIBTCC_INC)
|
||||||
$(CC) -o $@ -c $< $(NATIVE_DEFINES) $(CPPFLAGS) $(CFLAGS)
|
$(CC) -o $@ -c $< $(NATIVE_DEFINES) $(CPPFLAGS) $(CFLAGS)
|
||||||
|
|
||||||
|
ifndef LIBTCC_DLL
|
||||||
libtcc.a: $(LIBTCC_OBJ)
|
libtcc.a: $(LIBTCC_OBJ)
|
||||||
$(AR) rcs $@ $^
|
$(AR) rcs $@ $^
|
||||||
|
endif
|
||||||
|
|
||||||
libtcc.so.1.0: $(LIBTCC_OBJ)
|
libtcc.so.1.0: $(LIBTCC_OBJ)
|
||||||
$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
|
$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
libtcc.so.1.0: CFLAGS+=-fPIC
|
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
|
# windows utilities
|
||||||
tiny_impdef$(EXESUF): win32/tools/tiny_impdef.c
|
tiny_impdef$(EXESUF): win32/tools/tiny_impdef.c
|
||||||
$(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
|
$(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
|
||||||
@ -286,7 +299,8 @@ install: $(PROGS) $(TCCLIBS) $(TCCDOCS)
|
|||||||
cp -r $(top_srcdir)/win32/examples/. "$(tccdir)/examples"
|
cp -r $(top_srcdir)/win32/examples/. "$(tccdir)/examples"
|
||||||
$(INSTALL) -m644 $(addprefix $(top_srcdir)/include/,$(TCC_INCLUDES)) "$(tccdir)/include"
|
$(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 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
|
ifdef CONFIG_CROSS
|
||||||
mkdir -p "$(tccdir)/lib/32"
|
mkdir -p "$(tccdir)/lib/32"
|
||||||
mkdir -p "$(tccdir)/lib/64"
|
mkdir -p "$(tccdir)/lib/64"
|
||||||
|
13
arm-gen.c
13
arm-gen.c
@ -800,6 +800,19 @@ int assign_fpreg(struct avail_regs *avregs, int align, int size)
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
/* Generate function call. The function address is pushed first, then
|
||||||
all the parameters in call order. This functions pops all the
|
all the parameters in call order. This functions pops all the
|
||||||
parameters and the function address. */
|
parameters and the function address. */
|
||||||
|
35
i386-gen.c
35
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 fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
|
||||||
static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
|
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
|
/* Generate function call. The function address is pushed first, then
|
||||||
all the parameters in call order. This functions pops all the
|
all the parameters in call order. This functions pops all the
|
||||||
parameters and the function address. */
|
parameters and the function address. */
|
||||||
@ -444,10 +466,6 @@ ST_FUNC void gfunc_call(int nb_args)
|
|||||||
}
|
}
|
||||||
gcall_or_jmp(0);
|
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)
|
if (args_size && func_call != FUNC_STDCALL)
|
||||||
gadd_sp(args_size);
|
gadd_sp(args_size);
|
||||||
vtop--;
|
vtop--;
|
||||||
@ -491,7 +509,12 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
|||||||
/* if the function returns a structure, then add an
|
/* if the function returns a structure, then add an
|
||||||
implicit pointer parameter */
|
implicit pointer parameter */
|
||||||
func_vt = sym->type;
|
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) {
|
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
|
||||||
|
#endif
|
||||||
/* XXX: fastcall case ? */
|
/* XXX: fastcall case ? */
|
||||||
func_vc = addr;
|
func_vc = addr;
|
||||||
addr += 4;
|
addr += 4;
|
||||||
@ -526,10 +549,6 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
|||||||
/* pascal type call ? */
|
/* pascal type call ? */
|
||||||
if (func_call == FUNC_STDCALL)
|
if (func_call == FUNC_STDCALL)
|
||||||
func_ret_sub = addr - 8;
|
func_ret_sub = addr - 8;
|
||||||
#ifdef TCC_TARGET_PE
|
|
||||||
else if (func_vc)
|
|
||||||
func_ret_sub = 4;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
/* leave some room for bound checking code */
|
/* leave some room for bound checking code */
|
||||||
|
1
tcc.h
1
tcc.h
@ -1267,6 +1267,7 @@ ST_FUNC void gsym_addr(int t, int a);
|
|||||||
ST_FUNC void gsym(int t);
|
ST_FUNC void gsym(int t);
|
||||||
ST_FUNC void load(int r, SValue *sv);
|
ST_FUNC void load(int r, SValue *sv);
|
||||||
ST_FUNC void store(int r, SValue *v);
|
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_call(int nb_args);
|
||||||
ST_FUNC void gfunc_prolog(CType *func_type);
|
ST_FUNC void gfunc_prolog(CType *func_type);
|
||||||
ST_FUNC void gfunc_epilog(void);
|
ST_FUNC void gfunc_epilog(void);
|
||||||
|
67
tccgen.c
67
tccgen.c
@ -3850,7 +3850,7 @@ ST_FUNC void unary(void)
|
|||||||
} else if (tok == '(') {
|
} else if (tok == '(') {
|
||||||
SValue ret;
|
SValue ret;
|
||||||
Sym *sa;
|
Sym *sa;
|
||||||
int nb_args;
|
int nb_args, sret;
|
||||||
|
|
||||||
/* function call */
|
/* function call */
|
||||||
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
|
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
|
||||||
@ -3874,6 +3874,9 @@ ST_FUNC void unary(void)
|
|||||||
ret.r2 = VT_CONST;
|
ret.r2 = VT_CONST;
|
||||||
/* compute first implicit argument if a structure is returned */
|
/* compute first implicit argument if a structure is returned */
|
||||||
if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
|
if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
|
||||||
|
int ret_align;
|
||||||
|
sret = gfunc_sret(&s->type, &ret.type, &ret_align);
|
||||||
|
if (sret) {
|
||||||
/* get some space for the returned structure */
|
/* get some space for the returned structure */
|
||||||
size = type_size(&s->type, &align);
|
size = type_size(&s->type, &align);
|
||||||
loc = (loc - size) & -align;
|
loc = (loc - size) & -align;
|
||||||
@ -3884,8 +3887,13 @@ ST_FUNC void unary(void)
|
|||||||
vseti(VT_LOCAL, loc);
|
vseti(VT_LOCAL, loc);
|
||||||
ret.c = vtop->c;
|
ret.c = vtop->c;
|
||||||
nb_args++;
|
nb_args++;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
sret = 0;
|
||||||
ret.type = s->type;
|
ret.type = s->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sret) {
|
||||||
/* return in register */
|
/* return in register */
|
||||||
if (is_float(ret.type.t)) {
|
if (is_float(ret.type.t)) {
|
||||||
ret.r = reg_fret(ret.type.t);
|
ret.r = reg_fret(ret.type.t);
|
||||||
@ -3919,6 +3927,17 @@ ST_FUNC void unary(void)
|
|||||||
/* return value */
|
/* return value */
|
||||||
vsetc(&ret.type, ret.r, &ret.c);
|
vsetc(&ret.type, ret.r, &ret.c);
|
||||||
vtop->r2 = ret.r2;
|
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 {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -4466,30 +4485,11 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
|
|||||||
gexpr();
|
gexpr();
|
||||||
gen_assign_cast(&func_vt);
|
gen_assign_cast(&func_vt);
|
||||||
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
|
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
|
||||||
CType type;
|
CType type, ret_type;
|
||||||
|
int ret_align;
|
||||||
|
if (gfunc_sret(&func_vt, &ret_type, &ret_align)) {
|
||||||
/* if returning structure, must copy it to implicit
|
/* if returning structure, must copy it to implicit
|
||||||
first pointer arg location */
|
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;
|
|
||||||
addr = loc;
|
|
||||||
type = func_vt;
|
|
||||||
vset(&type, VT_LOCAL | VT_LVAL, addr);
|
|
||||||
vswap();
|
|
||||||
vstore();
|
|
||||||
vset(&int_type, VT_LOCAL | VT_LVAL, addr);
|
|
||||||
}
|
|
||||||
vtop->type = int_type;
|
|
||||||
gv(RC_IRET);
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
type = func_vt;
|
type = func_vt;
|
||||||
mk_pointer(&type);
|
mk_pointer(&type);
|
||||||
vset(&type, VT_LOCAL | VT_LVAL, func_vc);
|
vset(&type, VT_LOCAL | VT_LVAL, func_vc);
|
||||||
@ -4497,9 +4497,26 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
|
|||||||
vswap();
|
vswap();
|
||||||
/* copy structure value to pointer */
|
/* copy structure value to pointer */
|
||||||
vstore();
|
vstore();
|
||||||
#ifdef TCC_ARM_EABI
|
} 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(&ret_type, VT_LOCAL | VT_LVAL, addr);
|
||||||
|
}
|
||||||
|
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)) {
|
} else if (is_float(func_vt.t)) {
|
||||||
gv(rc_fret(func_vt.t));
|
gv(rc_fret(func_vt.t));
|
||||||
} else {
|
} else {
|
||||||
|
@ -13,7 +13,7 @@ TESTS = \
|
|||||||
hello-run \
|
hello-run \
|
||||||
libtest \
|
libtest \
|
||||||
test3 \
|
test3 \
|
||||||
abitest-exe \
|
abitest \
|
||||||
moretests
|
moretests
|
||||||
|
|
||||||
# test4 -- problem with -static
|
# test4 -- problem with -static
|
||||||
@ -180,12 +180,16 @@ asmtest: asmtest.ref
|
|||||||
|
|
||||||
# Check that code generated by libtcc is binary compatible with
|
# Check that code generated by libtcc is binary compatible with
|
||||||
# that generated by CC
|
# that generated by CC
|
||||||
abitest$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC)
|
abitest-cc$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC)
|
||||||
$(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir) -g -O0
|
$(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 ------------ $@ ------------
|
@echo ------------ $@ ------------
|
||||||
abitest$(EXESUF) lib_path=..
|
abitest-cc$(EXESUF) lib_path=..
|
||||||
|
abitest-tcc$(EXESUF) lib_path=..
|
||||||
|
|
||||||
# targets for development
|
# targets for development
|
||||||
%.bin: %.c tcc
|
%.bin: %.c tcc
|
||||||
|
@ -37,24 +37,62 @@ static int run_callback(const char *src, callback_type callback) {
|
|||||||
return result;
|
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) {
|
static int reg_pack_test_callback(void *ptr) {
|
||||||
test1_type r;
|
reg_pack_test_function_type f = (reg_pack_test_function_type)ptr;
|
||||||
r = ((test1_function_type)ptr)();
|
reg_pack_test_type a = {10, 35};
|
||||||
return ((r.x == 10) && (r.y == 35)) ? 0 : -1;
|
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 =
|
const char *src =
|
||||||
"typedef struct test1_type_s {int x, y;} test1_type;"
|
"typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;"
|
||||||
"test1_type f() {\n"
|
"reg_pack_test_type f(reg_pack_test_type a) {\n"
|
||||||
" test1_type r = {10, 35};\n"
|
" reg_pack_test_type r = {a.x*5, a.y*3};\n"
|
||||||
" return r;\n"
|
" return r;\n"
|
||||||
"}\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) \
|
#define RUN_TEST(t) \
|
||||||
@ -75,6 +113,7 @@ int main(int argc, char **argv) {
|
|||||||
if (argc == 2 && !memcmp(argv[1], "lib_path=",9))
|
if (argc == 2 && !memcmp(argv[1], "lib_path=",9))
|
||||||
tccdir = argv[1] + 9;
|
tccdir = argv[1] + 9;
|
||||||
|
|
||||||
RUN_TEST(test1);
|
RUN_TEST(reg_pack_test);
|
||||||
|
RUN_TEST(sret_test);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user