diff options
Diffstat (limited to 'tests/tcctest.c')
-rw-r--r-- | tests/tcctest.c | 222 |
1 files changed, 201 insertions, 21 deletions
diff --git a/tests/tcctest.c b/tests/tcctest.c index 0f71482..57670be 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -176,6 +176,11 @@ static int onetwothree = 123; #define B3 4 #endif +#ifdef __TINYC__ +/* We try to handle this syntax. Make at least sure it doesn't segfault. */ +char invalid_function_def()[] {} +#endif + #define __INT64_C(c) c ## LL #define INT64_MIN (-__INT64_C(9223372036854775807)-1) @@ -379,7 +384,7 @@ void macro_test(void) MF_s("hi"); MF_t("hi"); - /* test macro substituion inside args (should not eat stream) */ + /* test macro substitution inside args (should not eat stream) */ printf("qq=%d\n", qq(qq)(2)); /* test zero argument case. NOTE: gcc 2.95.x does not accept a @@ -399,7 +404,7 @@ comment substituted */ TEST2(); - /* And again when the name and parenthes are separated by a + /* And again when the name and parentheses are separated by a comment. */ TEST2 /* the comment */ (); @@ -1045,8 +1050,8 @@ int pad1; but __alignof__ returns the wrong result (4) because we can't store the alignment yet when specified on symbols directly (it's stored in the type so we'd need to make - a copy of it). -struct aligntest7 altest7[2] __attribute__((aligned(16)));*/ + a copy of it). -- FIXED */ +struct aligntest7 altest7[2] __attribute__((aligned(16))); struct aligntest8 { @@ -1156,8 +1161,8 @@ void struct_test() sizeof(altest5), __alignof__(altest5)); printf("altest6 sizeof=%d alignof=%d\n", sizeof(altest6), __alignof__(altest6)); - /*printf("altest7 sizeof=%d alignof=%d\n", - sizeof(altest7), __alignof__(altest7));*/ + printf("altest7 sizeof=%d alignof=%d\n", + sizeof(altest7), __alignof__(altest7)); /* empty structures (GCC extension) */ printf("sizeof(struct empty) = %d\n", sizeof(struct empty)); @@ -1404,6 +1409,15 @@ void optimize_out(void) if (defined_function() && 0) refer_to_undefined(); + if (0) { + (void)sizeof( ({ + do { } while (0); + 0; + }) ); + undefined_function(); + } + + /* Leave the "if(1)return; printf()" in this order and last in the function */ if (1) return; printf ("oor:%d\n", undefined_function()); @@ -1738,6 +1752,8 @@ arrtype2 sinit22 = {5,6,7}; int sinit23[2] = { "astring" ? sizeof("astring") : -1, &sinit23 ? 42 : -1 }; +extern int external_inited = 42; + void init_test(void) { int linit1 = 2; @@ -2028,13 +2044,6 @@ void bitfield_test(void) else printf("st1.f2 != -1\n"); -#ifndef __i386__ - /* on i386 we don't correctly support long long bit-fields. - The bitfields can straddle long long boundaries (at least with - GCC bitfield layout) and code generation isn't prepared for this - (would have to work with two words in that case). */ - /* bit sizes below must be bigger than 32 since GCC doesn't allow - long-long bitfields whose size is not bigger than int */ struct sbf2 { long long f1 : 45; long long : 2; @@ -2047,7 +2056,7 @@ void bitfield_test(void) st2.f3 = a; st2.f2++; printf("%lld %lld %lld\n", st2.f1, st2.f2, st2.f3); -#endif + #if 0 Disabled for now until further clarification re GCC compatibility struct sbf3 { @@ -2060,6 +2069,26 @@ void bitfield_test(void) } st3; printf("sizeof(st3) = %d\n", sizeof(st3)); #endif + + struct sbf4 { + int x : 31; + char y : 2; + } st4; + st4.y = 1; + printf("st4.y == %d\n", st4.y); + struct sbf5 { + int a; + char b; + int x : 12, y : 4, : 0, : 4, z : 3; + char c; + } st5 = { 1, 2, 3, 4, -3, 6 }; + printf("st5 = %d %d %d %d %d %d\n", st5.a, st5.b, st5.x, st5.y, st5.z, st5.c); + struct sbf6 { + short x : 12; + unsigned char y : 2; + } st6; + st6.y = 1; + printf("st6.y == %d\n", st6.y); } #ifdef __x86_64__ @@ -2658,6 +2687,9 @@ int reltab[3] = { 1, 2, 3 }; int *rel1 = &reltab[1]; int *rel2 = &reltab[2]; +#ifdef _WIN64 +void relocation_test(void) {} +#else void getmyaddress(void) { printf("in getmyaddress\n"); @@ -2686,6 +2718,7 @@ void relocation_test(void) printf("pa_symbol=0x%lx\n", __pa_symbol() >> 63); #endif } +#endif void old_style_f(a,b,c) int a, b; @@ -2866,6 +2899,11 @@ struct hlist_head { struct hlist_node *first, *last; }; +void consume_ulong (unsigned long i) +{ + i = 0; +} + void statement_expr_test(void) { int a, i; @@ -2921,6 +2959,9 @@ void statement_expr_test(void) }); printf ("stmtexpr: %d %d %d\n", t, b, c); printf ("stmtexpr: %ld %ld\n", (long)h.first, (long)h.last); + + /* Test that we can give out addresses of local labels. */ + consume_ulong(({ __label__ __here; __here: (unsigned long)&&__here; })); } void local_label_test(void) @@ -3076,7 +3117,7 @@ static __inline__ unsigned long long inc64(unsigned long long a) unsigned long long res; #ifdef __x86_64__ /* Using the A constraint is wrong, and increments are tested - elsewere. */ + elsewhere. */ res = a + 1; #else __asm__("addl $1, %%eax ; adcl $0, %%edx" : "=A" (res) : "A" (a)); @@ -3118,10 +3159,13 @@ void other_constraints_test(void) { unsigned long ret; int var; +#ifndef _WIN64 __asm__ volatile ("mov %P1,%0" : "=r" (ret) : "p" (&var)); printf ("oc1: %d\n", ret == (unsigned long)&var); +#endif } +#ifndef _WIN32 /* Test global asm blocks playing with aliases. */ void base_func(void) { @@ -3162,6 +3206,36 @@ char * get_asm_string (void) return str; } +/* This checks another constructs with local labels. */ +extern unsigned char alld_stuff[]; +asm(".data\n" + ".byte 41\n" + "alld_stuff:\n" + "661:\n" + ".byte 42\n" + "662:\n" + ".pushsection .data.ignore\n" + ".long 661b - .\n" /* This reference to 661 generates an external sym + which shouldn't somehow overwrite the offset that's + already determined for it. */ + ".popsection\n" + ".byte 662b - 661b\n" /* So that this value is undeniably 1. */); + +void asm_local_label_diff (void) +{ + printf ("asm_local_label_diff: %d %d\n", alld_stuff[0], alld_stuff[1]); +} + +/* This checks that static local variables are available from assembler. */ +void asm_local_statics (void) +{ + static int localint = 41; + asm("incl %0" : "+m" (localint)); + printf ("asm_local_statics: %d\n", localint); +} +#endif + +static unsigned int set; void fancy_copy (unsigned *in, unsigned *out) @@ -3174,7 +3248,7 @@ void fancy_copy2 (unsigned *in, unsigned *out) asm volatile ("mov %0,(%1)" : : "r" (*in), "r" (out) : "memory"); } -#ifdef __x86_64__ +#if defined __x86_64__ && !defined _WIN64 void clobber_r12(void) { asm volatile("mov $1, %%r12" ::: "r12"); @@ -3183,7 +3257,7 @@ void clobber_r12(void) void test_high_clobbers(void) { -#ifdef __x86_64__ +#if defined __x86_64__ && !defined _WIN64 register long val asm("r12"); long val2; /* This tests if asm clobbers correctly save/restore callee saved @@ -3249,6 +3323,84 @@ void trace_console(long len, long len2) } #endif } + +void test_asm_dead_code(void) +{ + long rdi; + /* Try to make sure that xdi contains a zero, and hence will + lead to a segfault if the next asm is evaluated without + arguments being set up. */ + asm volatile ("" : "=D" (rdi) : "0" (0)); + (void)sizeof (({ + int var; + /* This shouldn't trigger a segfault, either the argument + registers need to be set up and the asm emitted despite + this being in an unevaluated context, or both the argument + setup _and_ the asm emission need to be suppressed. The latter + is better. Disabling asm code gen when suppression is on + also fixes the above trace_console bug, but that came earlier + than asm suppression. */ + asm volatile ("movl $0,(%0)" : : "D" (&var) : "memory"); + var; + })); +} + +void test_asm_call(void) +{ +#if defined __x86_64__ && !defined _WIN64 + static char str[] = "PATH"; + char *s; + /* This tests if a reference to an undefined symbol from an asm + block, which isn't otherwise referenced in this file, is correctly + regarded as global symbol, so that it's resolved by other object files + or libraries. We chose getenv here, which isn't used anywhere else + in this file. (If we used e.g. printf, which is used we already + would have a global symbol entry, not triggering the bug which is + tested here). */ + /* two pushes so stack remains aligned */ + asm volatile ("push %%rdi; push %%rdi; mov %0, %%rdi;" +#if 1 && !defined(__TINYC__) && (defined(__PIC__) || defined(__PIE__)) + "call getenv@plt;" +#else + "call getenv;" +#endif + "pop %%rdi; pop %%rdi" + : "=a" (s) : "r" (str)); + printf("asmd: %s\n", s); +#endif +} + +#if defined __x86_64__ +# define RX "(%rip)" +#else +# define RX +#endif + +void asm_dot_test(void) +{ + int x; + for (x = 1;; ++x) { + int r = x; + switch (x) { + case 1: + asm(".text; lea S"RX",%eax; lea ."RX",%ecx; sub %ecx,%eax; S=.; jmp p0"); + case 2: + asm(".text; jmp .+6; .int 123; mov .-4"RX",%eax; jmp p0"); + case 3: + asm(".data; Y=.; .int 999; X=Y; .int 456; X=.-4"); + asm(".text; mov X"RX",%eax; jmp p0"); + case 4: + asm(".data; X=.; .int 789; Y=.; .int 999"); + asm(".text; mov X"RX",%eax; X=Y; jmp p0"); + case 0: + asm(".text; p0=.; mov %%eax,%0;" : "=m"(r)); break; + } + if (r == x) + break; + printf("asm_dot_test %d: %d\n", x, r); + } +} + void asm_test(void) { char buf[128]; @@ -3301,12 +3453,17 @@ void asm_test(void) printf("set=0x%x\n", set); val = 0x01020304; printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val)); +#ifndef _WIN32 override_func1(); override_func2(); /* The base_func ref from the following inline asm should find the global one, not the local decl from this function. */ asm volatile(".weak override_func3\n.set override_func3, base_func"); override_func3(); + printf("asmstr: %s\n", get_asm_string()); + asm_local_label_diff(); + asm_local_statics(); +#endif /* Check that we can also load structs of appropriate layout into registers. */ asm volatile("" : "=r" (asmret) : "0"(s2)); @@ -3319,7 +3476,6 @@ void asm_test(void) if (!somebool) printf("asmbool: failed\n"); #endif - printf("asmstr: %s\n", get_asm_string()); val = 43; fancy_copy (&val, &val2); printf ("fancycpy(%d)=%d\n", val, val2); @@ -3330,6 +3486,9 @@ void asm_test(void) printf ("regvar=%x\n", regvar); test_high_clobbers(); trace_console(8, 8); + test_asm_dead_code(); + test_asm_call(); + asm_dot_test(); return; label1: goto label2; @@ -3387,7 +3546,7 @@ void builtin_test(void) i = sizeof (__builtin_choose_expr (0, ll, s)); printf("bce: %d\n", i); - printf("bera: %p\n", __builtin_extract_return_addr((void*)43)); + //printf("bera: %p\n", __builtin_extract_return_addr((void*)43)); } #ifndef _WIN32 @@ -3657,8 +3816,6 @@ typedef struct __attribute__((__packed__)) { int c; } Spacked2; Spacked2 spacked2; -/* This doesn't work for now. Requires adjusting field offsets/sizes - after parsing the struct members. */ typedef struct Spacked3_s { char a; short b; @@ -3677,10 +3834,12 @@ typedef struct gate_struct64 gate_desc; gate_desc a_gate_desc; void attrib_test(void) { +#ifndef _WIN32 printf("attr: %d %d %d %d\n", sizeof(struct Spacked), sizeof(spacked), sizeof(Spacked2), sizeof(spacked2)); printf("attr: %d %d\n", sizeof(Spacked3), sizeof(spacked3)); printf("attr: %d %d\n", sizeof(gate_desc), sizeof(a_gate_desc)); +#endif } extern __attribute__((__unused__)) char * __attribute__((__unused__)) * strange_attrib_placement (void); @@ -3689,3 +3848,24 @@ void * __attribute__((__unused__)) get_void_ptr (void *a) { return a; } + +/* This part checks for a bug in TOK_GET (used for inline expansion), + where the large long long constant left the the high bits set for + the integer constant token. */ +static inline +int __get_order(unsigned long long size) +{ + int order; + size -= 0xffff880000000000ULL; // this const left high bits set in the token + { + struct S { int i : 1; } s; // constructed for this '1' + } + order = size; + return order; +} + +/* This just forces the above inline function to be actually emitted. */ +int force_get_order(unsigned long s) +{ + return __get_order(s); +} |