tcctest.c: sizeof (long) != 8

Bad assumption make bad things happen:

    long d3;
    asm(..."1:\tdec %3\n\t" : ... "=&c" (d3)

Which wants 'dec RDI' but did 'dec EDI' on _WIN64.

Also:
- tcctest.c: enable more asm tests for win64
- configure: show errors if any with 'gcc conftest.c'
- tccgen.c: remove decl0(x, y, z)
This commit is contained in:
grischka 2022-10-14 20:10:38 +02:00
parent c60f1d953c
commit bb80cbe0d9
3 changed files with 46 additions and 47 deletions

2
configure vendored
View File

@ -357,7 +357,7 @@ fi
if test -z "$cross_prefix" ; then if test -z "$cross_prefix" ; then
CONFTEST=./conftest$EXESUF CONFTEST=./conftest$EXESUF
if ! $cc -o $CONFTEST $source_path/conftest.c 2>/dev/null ; then if ! $cc -o $CONFTEST $source_path/conftest.c ; then
echo "configure: error: '$cc' failed to compile conftest.c." echo "configure: error: '$cc' failed to compile conftest.c."
else else
cc_name="$($CONFTEST compiler)" cc_name="$($CONFTEST compiler)"

View File

@ -130,8 +130,7 @@ static void init_putv(init_params *p, CType *type, unsigned long c);
static void decl_initializer(init_params *p, CType *type, unsigned long c, int flags); static void decl_initializer(init_params *p, CType *type, unsigned long c, int flags);
static void block(int is_expr); static void block(int is_expr);
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);
static void decl(int l); static int decl(int l);
static int decl0(int l, int is_for_loop_init, Sym *);
static void expr_eq(void); static void expr_eq(void);
static void vpush_type_size(CType *type, int *a); static void vpush_type_size(CType *type, int *a);
static int is_compatible_unqualified_types(CType *type1, CType *type2); static int is_compatible_unqualified_types(CType *type1, CType *type2);
@ -6881,7 +6880,7 @@ again:
skip('('); skip('(');
if (tok != ';') { if (tok != ';') {
/* c99 for-loop init decl? */ /* c99 for-loop init decl? */
if (!decl0(VT_LOCAL, 1, NULL)) { if (!decl(VT_JMP)) {
/* no, regular for-loop init expr */ /* no, regular for-loop init expr */
gexpr(); gexpr();
vpop(); vpop();
@ -7795,7 +7794,7 @@ static void decl_initializer(init_params *p, CType *type, unsigned long c, int f
is put in the value stack. If 'has_init' is 2, a special parsing is put in the value stack. If 'has_init' is 2, a special parsing
is done to handle string constants. */ is done to handle string constants. */
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
int has_init, int v, int scope) int has_init, int v, int global)
{ {
int size, align, addr; int size, align, addr;
TokenString *init_str = NULL; TokenString *init_str = NULL;
@ -7932,7 +7931,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
} }
} else { } else {
sym = NULL; sym = NULL;
if (v && scope == VT_CONST) { if (v && global) {
/* see if the symbol was already defined */ /* see if the symbol was already defined */
sym = sym_find(v); sym = sym_find(v);
if (sym) { if (sym) {
@ -8198,9 +8197,10 @@ static void free_inline_functions(TCCState *s)
dynarray_reset(&s->inline_fns, &s->nb_inline_fns); dynarray_reset(&s->inline_fns, &s->nb_inline_fns);
} }
/* 'l' is VT_LOCAL or VT_CONST to define default storage type, or VT_CMP /* 'l' is VT_LOCAL or VT_CONST to define default storage type
if parsing old style parameter decl list (and FUNC_SYM is set then) */ or VT_CMP if parsing old style parameter list
static int decl0(int l, int is_for_loop_init, Sym *func_sym) or VT_JMP if parsing c99 for decl: for (int i = 0, ...) */
static int decl(int l)
{ {
int v, has_init, r, oldint; int v, has_init, r, oldint;
CType type, btype; CType type, btype;
@ -8236,7 +8236,7 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
oldint = 0; oldint = 0;
if (!parse_btype(&btype, &adbase, l == VT_LOCAL)) { if (!parse_btype(&btype, &adbase, l == VT_LOCAL)) {
if (is_for_loop_init) if (l == VT_JMP)
return 0; return 0;
/* skip redundant ';' if not in old parameter decl scope */ /* skip redundant ';' if not in old parameter decl scope */
if (tok == ';' && l != VT_CMP) { if (tok == ';' && l != VT_CMP) {
@ -8288,13 +8288,15 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
} }
#endif #endif
if ((type.t & VT_BTYPE) == VT_FUNC) { if ((type.t & VT_BTYPE) == VT_FUNC) {
if ((type.t & VT_STATIC) && (l == VT_LOCAL)) if ((type.t & VT_STATIC) && (l != VT_CONST))
tcc_error("function without file scope cannot be static"); tcc_error("function without file scope cannot be static");
/* if old style function prototype, we accept a /* if old style function prototype, we accept a
declaration list */ declaration list */
sym = type.ref; sym = type.ref;
if (sym->f.func_type == FUNC_OLD && l == VT_CONST) if (sym->f.func_type == FUNC_OLD && l == VT_CONST) {
decl0(VT_CMP, 0, sym); func_vt = type;
decl(VT_CMP);
}
#if defined TCC_TARGET_MACHO || defined TARGETOS_ANDROID #if defined TCC_TARGET_MACHO || defined TARGETOS_ANDROID
if (sym->f.func_alwinl if (sym->f.func_alwinl
&& ((type.t & (VT_EXTERN | VT_INLINE)) && ((type.t & (VT_EXTERN | VT_INLINE))
@ -8388,12 +8390,12 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
} else { } else {
if (l == VT_CMP) { if (l == VT_CMP) {
/* find parameter in function parameter list */ /* find parameter in function parameter list */
for (sym = func_sym->next; sym; sym = sym->next) for (sym = func_vt.ref->next; sym; sym = sym->next)
if ((sym->v & ~SYM_FIELD) == v) if ((sym->v & ~SYM_FIELD) == v)
goto found; goto found;
tcc_error("declaration for parameter '%s' but no such parameter", tcc_error("declaration for parameter '%s' but no such parameter",
get_tok_str(v, NULL)); get_tok_str(v, NULL));
found: found:
if (type.t & VT_STORAGE) /* 'register' is okay */ if (type.t & VT_STORAGE) /* 'register' is okay */
tcc_error("storage class specified for '%s'", tcc_error("storage class specified for '%s'",
get_tok_str(v, NULL)); get_tok_str(v, NULL));
@ -8460,20 +8462,20 @@ found:
esym->st_value, esym->st_size, 1); esym->st_value, esym->st_size, 1);
} }
} else { } else {
if (type.t & VT_STATIC) if (l == VT_CONST || (type.t & VT_STATIC))
r |= VT_CONST; r |= VT_CONST;
else else
r |= l; r |= VT_LOCAL;
if (has_init) if (has_init)
next(); next();
else if (l == VT_CONST) else if (l == VT_CONST)
/* uninitialized global variables may be overridden */ /* uninitialized global variables may be overridden */
type.t |= VT_EXTERN; type.t |= VT_EXTERN;
decl_initializer_alloc(&type, &ad, r, has_init, v, l); decl_initializer_alloc(&type, &ad, r, has_init, v, l == VT_CONST);
} }
} }
if (tok != ',') { if (tok != ',') {
if (is_for_loop_init) if (l == VT_JMP)
return 1; return 1;
skip(';'); skip(';');
break; break;
@ -8485,11 +8487,6 @@ found:
return 0; return 0;
} }
static void decl(int l)
{
decl0(l, 0, NULL);
}
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
#undef gjmp_addr #undef gjmp_addr
#undef gjmp #undef gjmp

View File

@ -3251,10 +3251,12 @@ void local_label_test(void)
/* inline assembler test */ /* inline assembler test */
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
typedef __SIZE_TYPE__ word;
/* from linux kernel */ /* from linux kernel */
static char * strncat1(char * dest,const char * src,size_t count) static char * strncat1(char * dest,const char * src,size_t count)
{ {
long d0, d1, d2, d3; word d0, d1, d2, d3;
__asm__ __volatile__( __asm__ __volatile__(
"repne\n\t" "repne\n\t"
"scasb\n\t" "scasb\n\t"
@ -3276,7 +3278,7 @@ return dest;
static char * strncat2(char * dest,const char * src,size_t count) static char * strncat2(char * dest,const char * src,size_t count)
{ {
long d0, d1, d2, d3; word d0, d1, d2, d3;
__asm__ __volatile__( __asm__ __volatile__(
"repne scasb\n\t" /* one-line repne prefix + string op */ "repne scasb\n\t" /* one-line repne prefix + string op */
"dec %1\n\t" "dec %1\n\t"
@ -3297,7 +3299,7 @@ return dest;
static inline void * memcpy1(void * to, const void * from, size_t n) static inline void * memcpy1(void * to, const void * from, size_t n)
{ {
size_t d0, d1, d2; word d0, d1, d2;
__asm__ __volatile__( __asm__ __volatile__(
"rep ; movsl\n\t" "rep ; movsl\n\t"
"testb $2,%b4\n\t" "testb $2,%b4\n\t"
@ -3308,14 +3310,14 @@ __asm__ __volatile__(
"movsb\n" "movsb\n"
"2:" "2:"
: "=&c" (d0), "=&D" (d1), "=&S" (d2) : "=&c" (d0), "=&D" (d1), "=&S" (d2)
:"0" (n/4), "q" (n),"1" ((size_t) to),"2" ((size_t) from) :"0" (n/4), "q" (n),"1" ((word) to),"2" ((word) from)
: "memory"); : "memory");
return (to); return (to);
} }
static inline void * memcpy2(void * to, const void * from, size_t n) static inline void * memcpy2(void * to, const void * from, size_t n)
{ {
size_t d0, d1, d2; word d0, d1, d2;
__asm__ __volatile__( __asm__ __volatile__(
"rep movsl\n\t" /* one-line rep prefix + string op */ "rep movsl\n\t" /* one-line rep prefix + string op */
"testb $2,%b4\n\t" "testb $2,%b4\n\t"
@ -3326,7 +3328,7 @@ __asm__ __volatile__(
"movsb\n" "movsb\n"
"2:" "2:"
: "=&c" (d0), "=&D" (d1), "=&S" (d2) : "=&c" (d0), "=&D" (d1), "=&S" (d2)
:"0" (n/4), "q" (n),"1" ((size_t) to),"2" ((size_t) from) :"0" (n/4), "q" (n),"1" ((word) to),"2" ((word) from)
: "memory"); : "memory");
return (to); return (to);
} }
@ -3395,12 +3397,12 @@ struct struct123 {
int b; int b;
}; };
struct struct1231 { struct struct1231 {
unsigned long addr; word addr;
}; };
unsigned long mconstraint_test(struct struct1231 *r) word mconstraint_test(struct struct1231 *r)
{ {
unsigned long ret; word ret;
unsigned int a[2]; unsigned int a[2];
a[0] = 0; a[0] = 0;
__asm__ volatile ("lea %2,%0; movl 4(%0),%k0; addl %2,%k0; movl $51,%2; movl $52,4%2; movl $63,%1" __asm__ volatile ("lea %2,%0; movl 4(%0),%k0; addl %2,%k0; movl $51,%2; movl $52,4%2; movl $63,%1"
@ -3422,11 +3424,11 @@ int fls64(unsigned long long x)
void other_constraints_test(void) void other_constraints_test(void)
{ {
unsigned long ret; word ret;
int var; int var;
#if !defined(_WIN64) && CC_NAME != CC_clang #if CC_NAME != CC_clang
__asm__ volatile ("mov %P1,%0" : "=r" (ret) : "p" (&var)); __asm__ volatile ("mov %P1,%0" : "=r" (ret) : "p" (&var));
printf ("oc1: %d\n", ret == (unsigned long)&var); printf ("oc1: %d\n", ret == (word)&var);
#endif #endif
} }
@ -3510,6 +3512,7 @@ void asm_local_label_diff (void)
printf ("asm_local_label_diff: %d %d\n", alld_stuff[0], alld_stuff[1]); printf ("asm_local_label_diff: %d %d\n", alld_stuff[0], alld_stuff[1]);
} }
#endif #endif
#endif
/* This checks that static local variables are available from assembler. */ /* This checks that static local variables are available from assembler. */
void asm_local_statics (void) void asm_local_statics (void)
@ -3518,7 +3521,6 @@ void asm_local_statics (void)
asm("incl %0" : "+m" (localint)); asm("incl %0" : "+m" (localint));
printf ("asm_local_statics: %d\n", localint); printf ("asm_local_statics: %d\n", localint);
} }
#endif
static static
unsigned int set; unsigned int set;
@ -3533,7 +3535,7 @@ void fancy_copy2 (unsigned *in, unsigned *out)
asm volatile ("mov %0,(%1)" : : "r" (*in), "r" (out) : "memory"); asm volatile ("mov %0,(%1)" : : "r" (*in), "r" (out) : "memory");
} }
#if defined __x86_64__ && !defined _WIN64 #if defined __x86_64__
void clobber_r12(void) void clobber_r12(void)
{ {
asm volatile("mov $1, %%r12" ::: "r12"); asm volatile("mov $1, %%r12" ::: "r12");
@ -3542,9 +3544,9 @@ void clobber_r12(void)
void test_high_clobbers_really(void) void test_high_clobbers_really(void)
{ {
#if defined __x86_64__ && !defined _WIN64 #if defined __x86_64__
register long val asm("r12"); register word val asm("r12");
long val2; word val2;
/* This tests if asm clobbers correctly save/restore callee saved /* This tests if asm clobbers correctly save/restore callee saved
registers if they are clobbered and if it's the high 8 x86-64 registers if they are clobbered and if it's the high 8 x86-64
registers. This is fragile for GCC as the constraints do not registers. This is fragile for GCC as the constraints do not
@ -3558,8 +3560,8 @@ void test_high_clobbers_really(void)
void test_high_clobbers(void) void test_high_clobbers(void)
{ {
#if defined __x86_64__ && !defined _WIN64 #if defined __x86_64__
long x1, x2; word x1, x2;
asm volatile("mov %%r12,%0" :: "m" (x1)); /* save r12 */ asm volatile("mov %%r12,%0" :: "m" (x1)); /* save r12 */
test_high_clobbers_really(); test_high_clobbers_really();
asm volatile("mov %%r12,%0" :: "m" (x2)); /* new r12 */ asm volatile("mov %%r12,%0" :: "m" (x2)); /* new r12 */
@ -3625,7 +3627,7 @@ void trace_console(long len, long len2)
void test_asm_dead_code(void) void test_asm_dead_code(void)
{ {
long rdi; word rdi;
/* Try to make sure that xdi contains a zero, and hence will /* Try to make sure that xdi contains a zero, and hence will
lead to a segfault if the next asm is evaluated without lead to a segfault if the next asm is evaluated without
arguments being set up. */ arguments being set up. */
@ -3727,12 +3729,12 @@ void asm_test(void)
char buf[128]; char buf[128];
unsigned int val, val2; unsigned int val, val2;
struct struct123 s1; struct struct123 s1;
struct struct1231 s2 = { (unsigned long)&s1 }; struct struct1231 s2 = { (word)&s1 };
/* Hide the outer base_func, but check later that the inline /* Hide the outer base_func, but check later that the inline
asm block gets the outer one. */ asm block gets the outer one. */
int base_func = 42; int base_func = 42;
void override_func3 (void); void override_func3 (void);
unsigned long asmret; word asmret;
#ifdef BOOL_ISOC99 #ifdef BOOL_ISOC99
_Bool somebool; _Bool somebool;
#endif #endif
@ -3783,8 +3785,8 @@ void asm_test(void)
printf("asmstr: %s\n", get_asm_string()); printf("asmstr: %s\n", get_asm_string());
asm_local_label_diff(); asm_local_label_diff();
#endif #endif
asm_local_statics();
#endif #endif
asm_local_statics();
#ifndef __clang__ #ifndef __clang__
/* clang can't deal with the type change */ /* clang can't deal with the type change */
/* Check that we can also load structs of appropriate layout /* Check that we can also load structs of appropriate layout