summaryrefslogtreecommitdiff
path: root/tests/tcctest.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/tcctest.c')
-rw-r--r--tests/tcctest.c222
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);
+}