tinycc/tests/tests2/101_cleanup.c
herman ten brugge b6a16e3be4
Some checks failed
build and test / test-x86_64-linux (push) Has been cancelled
build and test / test-x86_64-osx (push) Has been cancelled
build and test / test-aarch64-osx (push) Has been cancelled
build and test / test-x86-win32 (push) Has been cancelled
build and test / test-armv7-linux (push) Has been cancelled
build and test / test-aarch64-linux (push) Has been cancelled
build and test / test-riscv64-linux (push) Has been cancelled
Save registers around attribute cleanup
This makes attribute cleanup code work the same as gcc and also
makes bound checking a very little bit faster.

tcc.h:
  Add save_return_reg(CType *) and restore_return_reg(CType *)
  Change gfunc_epilog() to gfunc_epilog(Sym *)

arm-gen.c:
arm64-gen.c:
c67-gen.c:
i386-gen.c:
il-gen.c:
riscv64-gen.c:
x86_64-gen.c:
  Move save and restore register around bound_local_delete call
  to save_return_reg and restore_return_reg.
  Pass func_type from gfunc_epilog to gen_bounds_epilog.

tccgen.c:
  Call save_return_reg/restore_return_reg in try_call_scope_cleanup
  when RETURN is found.

tccrun.c:
  Fix warning when bound checking not used.

tests/tests2/101_cleanup.c
tests/tests2/101_cleanup.expect
  Extra checks attribute cleanup save/restore registers.

tests/tests2/Makefile:
  Fix when bound checking not used.
2025-05-22 16:58:12 +02:00

310 lines
6.2 KiB
C

extern int printf(const char*, ...);
static int glob_i = 0;
typedef struct { int a; int b; int c; int d; int e; int f; int g; int h; } tstl;
typedef struct { int a; int b; int c; int d; } tsti;
typedef struct { double a; double b; } tstd;
typedef struct { long double a; } tstld;
void incr_glob_i(int *i)
{
glob_i += *i;
*i = -1;
}
#define INCR_GI { \
int i __attribute__ ((__cleanup__(incr_glob_i))) = 1; \
}
#define INCR_GI0 INCR_GI INCR_GI INCR_GI INCR_GI
#define INCR_GI1 INCR_GI0 INCR_GI0 INCR_GI0 INCR_GI0
#define INCR_GI2 INCR_GI1 INCR_GI1 INCR_GI1 INCR_GI1
#define INCR_GI3 INCR_GI2 INCR_GI2 INCR_GI2 INCR_GI2
#define INCR_GI4 INCR_GI3 INCR_GI3 INCR_GI3 INCR_GI3
#define INCR_GI5 INCR_GI4 INCR_GI4 INCR_GI4 INCR_GI4
#define INCR_GI6 INCR_GI5 INCR_GI5 INCR_GI5 INCR_GI5
#define INCR_GI7 INCR_GI6 INCR_GI6 INCR_GI6 INCR_GI6
void check2(char **hum);
void check(int *j)
{
char * __attribute__ ((cleanup(check2))) stop_that = "wololo";
int chk = 0;
{
char * __attribute__ ((cleanup(check2))) stop_that = "plop";
{
non_plopage:
printf("---- %d\n", chk);
}
if (!chk) {
chk = 1;
goto non_plopage;
}
}
{
char * __attribute__ ((cleanup(check2))) stop_that = "tata !";
goto out;
stop_that = "titi";
}
again:
chk = 2;
{
char * __attribute__ ((cleanup(check2))) cascade1 = "1";
{
char * __attribute__ ((cleanup(check2))) cascade2 = "2";
{
char * __attribute__ ((cleanup(check2))) cascade3 = "3";
goto out;
cascade3 = "nope";
}
}
}
out:
if (chk != 2)
goto again;
{
{
char * __attribute__ ((cleanup(check2))) out = "last goto out";
++chk;
if (chk != 3)
goto out;
}
}
*j = -1;
return;
}
void check_oh_i(char *oh_i)
{
printf("c: %c\n", *oh_i);
*oh_i = '0';
}
void goto_hell(double *f)
{
printf("oo: %f\n", *f);
*f = -1.0;
}
char *test()
{
char *__attribute__ ((cleanup(check2))) str = "I don't think this should be print(but gcc got it wrong too)";
return str;
}
void test_ret_subcall(char *that)
{
printf("should be print before\n");
}
void test_ret()
{
char *__attribute__ ((cleanup(check2))) that = "that";
return test_ret_subcall(that);
}
void test_ret2()
{
char *__attribute__ ((cleanup(check2))) that = "-that";
{
char *__attribute__ ((cleanup(check2))) that = "this should appear only once";
}
{
char *__attribute__ ((cleanup(check2))) that = "-that2";
return;
}
}
void test2(void) {
int chk = 0;
again:
if (!chk) {
char * __attribute__ ((cleanup(check2))) stop_that = "test2";
chk++;
goto again;
}
}
int test3(void) {
char * __attribute__ ((cleanup(check2))) stop_that = "three";
int chk = 0;
if (chk) {
{
outside:
{
char * __attribute__ ((cleanup(check2))) stop_that = "two";
printf("---- %d\n", chk);
}
}
}
if (!chk)
{
char * __attribute__ ((cleanup(check2))) stop_that = "one";
if (!chk) {
chk = 1;
goto outside;
}
}
return 0;
}
void cl(int *ip)
{
printf("%d\n", *ip);
*ip = -1;
}
void loop_cleanups(void)
{
__attribute__((cleanup(cl))) int l = 1000;
printf("-- loop 0 --\n");
for ( __attribute__((cleanup(cl))) int i = 0; i < 10; ++i) {
__attribute__((cleanup(cl))) int j = 100;
}
printf("-- loop 1 --\n");
for (__attribute__((cleanup(cl))) int i = 0; i < 10; ++i) {
__attribute__((cleanup(cl))) int j = 200;
continue;
}
printf("-- loop 2 --\n");
for (__attribute__((cleanup(cl))) int i = 0; i < 10; ++i) {
__attribute__((cleanup(cl))) int j = 300;
break;
}
printf("-- loop 3 --\n");
for (int i = 0; i < 2; ++i) {
__attribute__((cleanup(cl))) int j = 400;
switch (i) {
case 0:
continue;
default:
{
__attribute__((cleanup(cl))) int jj = 500;
break;
}
}
}
printf("after break\n");
}
void my_cleanup1(int *p) {
printf("%d\n", *p);
*p = 0x90;
}
int test_cleanup1(void) {
int __attribute__((cleanup(my_cleanup1))) n = 42;
return n;
}
void my_cleanup2(tstl *p) {
printf("%d %d %d %d %d %d %d %d\n", p->a, p->b, p->c, p->d,
p->e, p->f, p->g, p->h);
p->a = 0x90; p->b = 0x91; p->c = 0x92; p->d = 0x93;
p->e = 0x94; p->f = 0x95; p->g = 0x96; p->h = 0x97;
}
tstl test_cleanup2(void) {
tstl __attribute__((cleanup(my_cleanup2))) n;
n.a = 42; n.b = 43; n.c = 44; n.d = 45;
n.e = 46; n.f = 47; n.g = 48; n.h = 49;
return n;
}
void my_cleanup3(tsti *p) {
printf("%d %d %d %d\n", p->a, p->b, p->c, p->d);
p->a = 0x90; p->b = 0x91; p->c = 0x92; p->d = 0x93;
}
tsti test_cleanup3(void) {
tsti __attribute__((cleanup(my_cleanup3))) n;
n.a = 42; n.b = 43; n.c = 44; n.d = 45;
return n;
}
void my_cleanup4(tstd *p) {
printf("%g %g\n", p->a, p->b);
p->a = 90.0; p->b = 91.0;
}
tstd test_cleanup4(void) {
tstd __attribute__((cleanup(my_cleanup4))) n;
n.a = 42.0; n.b = 43.0;
return n;
}
void my_cleanup5(tstld *p) {
printf("%Lf\n", p->a);
p->a = 90.0;
}
tstld test_cleanup5(void) {
tstld __attribute__((cleanup(my_cleanup5))) n;
n.a = 42.0;
return n;
}
int main()
{
int i __attribute__ ((__cleanup__(check))) = 0, not_i;
int chk = 0;
(void)not_i;
tstl tl;
tsti ti;
tstd td;
tstld tld;
{
__attribute__ ((__cleanup__(check_oh_i))) char oh_i = 'o', o = 'a';
}
INCR_GI7;
printf("glob_i: %d\n", glob_i);
naaaaaaaa:
if (!chk) {
__attribute__ ((__cleanup__(check_oh_i))) char oh_i = 'f';
double __attribute__ ((__cleanup__(goto_hell))) f = 2.6;
chk = 1;
goto naaaaaaaa;
}
i = 105;
printf("because what if free was call inside cleanup function %s\n", test());
test_ret();
test_ret2();
test2();
test3();
loop_cleanups();
printf("%d\n", test_cleanup1());
tl = test_cleanup2();
printf("%d %d %d %d %d %d %d %d\n", tl.a, tl.b, tl.c, tl.d,
tl.e, tl.f, tl.g, tl.h);
ti = test_cleanup3();
printf("%d %d %d %d\n", ti.a, ti.b, ti.c, ti.d);
td = test_cleanup4();
printf("%g %g\n", td.a, td.b);
tld = test_cleanup5();
printf("%Lf\n", tld.a);
return i;
}
void check2(char **hum)
{
printf("str: %s\n", *hum);
*hum = "fail";
}